diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..072c0c22b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespaces = true +indent_style = tab +indent_size = 2 diff --git a/.htaccess b/.htaccess index 80d7e878f..d83443d97 100644 --- a/.htaccess +++ b/.htaccess @@ -1,3 +1,5 @@ +Options -Indexes + RewriteEngine On RewriteRule ^favicon.ico$ styles/bootstrap/favicon.ico [L] @@ -6,6 +8,10 @@ RewriteRule ^favicon.ico$ styles/bootstrap/favicon.ico [L] RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$ RewriteRule ^.*$ - [E=CWD:%2] +# Do not allow access on the other directories in www +RewriteRule "^utils/.*$" "" [F] +RewriteRule "^doc/.*$" "" [F] + # Anything below the following dirs will never be rewritten RewriteRule "^pdfviewer/.*$" "-" [L] RewriteRule "^views/bootstrap/images.*$" "-" [L] diff --git a/CHANGELOG b/CHANGELOG index c177f03ae..2e5920150 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,15 +1,36 @@ -------------------------------------------------------------------------------- Changes in version 6.1.0 -------------------------------------------------------------------------------- -- merge changes up to 6.0.3 +- merge changes up to 6.0.9 - add attribute groups and selective output of attributes +-------------------------------------------------------------------------------- + Changes in version 6.0.9 +-------------------------------------------------------------------------------- +- fix removal of roles (Closes: #465) +- fix password forgotten process + +-------------------------------------------------------------------------------- + Changes in version 6.0.8 +-------------------------------------------------------------------------------- +- merge changes up to 5.1.15 +- fix syntax error in op/op.EditComment.php +- fix use of private variable in op/op.SetRecipients.php and op/op.SetRevisors.php +- fix triggering a transition in advanced workflow mode + -------------------------------------------------------------------------------- Changes in version 6.0.7 -------------------------------------------------------------------------------- - fix editing of document attachments - make receipt summary look like approval/review summary -- merge changes up to 5.1.10 +- merge changes up to 5.1.14 +- do not show the updating user in a revision workflow if the status is 0 + this is misleading because the user starting the revision workflow is the one + first accessing the document +- rejection of document receipts are turned off by default, but can be turned + on in the settings +- documents in DocumentChooser are sorted by name +- instead of just removing a user from all processes it can be replaced by a new user -------------------------------------------------------------------------------- Changes in version 6.0.6 @@ -116,6 +137,100 @@ - add document list which can be exported as an archive - search results can be exported +-------------------------------------------------------------------------------- + Changes in version 5.1.16 +-------------------------------------------------------------------------------- +- initialize categories to empty array. Closes #458 +- add new parameter $skipcont to hook folderListitem() +- use standard output format for documents and folders on ManageNotify page + +-------------------------------------------------------------------------------- + Changes in version 5.1.15 +-------------------------------------------------------------------------------- +- Improved import from file system +- HTTP Proxy for access on external extension repository can be set +- Do not use unzip in ExtensionMgr anymore +- fix version compare on info page +- allow one page mode on search page +- fix import of older extension versions from repository + +-------------------------------------------------------------------------------- + Changes in version 5.1.14 +-------------------------------------------------------------------------------- +- allow mimetype to specify documents which can be edited online +- show number of indexing tasks in progress bar +- fix comparison of last indexing time with creation date of document content +- new hooks leftContentPre and leftContentPost +- minimize sql queries when fetching sub folders and documents of a folder +- custom attributes can be validated in a hook +- document attributes comment, keywords, categories, expiration date, and sequence + can be turned off in the configuration +- workflows can be turned off completely +- Extension can be enabled/disabled in the extension manager, the previously + used method by setting a parameter in the extension's config file will no + longer work. +- clean up code for managing extensions +- fix renaming of folders via webdav +- fix list of expired documents on MyDocuments page +- pass showtree to ViewDocument (Closes: #462) +- fix upgrade script for sqlite3 + +-------------------------------------------------------------------------------- + Changes in version 5.1.13 +-------------------------------------------------------------------------------- +- make use of backup dir, do not allow backup if backup dir is not set +- the referer parameter in op/op.Settings.php is turned into an url before used + for redirect +- Import from filesystem can read a file with metadata +- drop folder chooser can be put multiple times on a page +- add section in README.Install.md on how to secure the configuration +- fix php error when removing a version of a document +- major rework of ViewFolder page, most parts of the page are now loaded by ajax +- do not set mandatory reviewer when document is uploaded and workflow mode is + set to 'traditional without review'. +- turn off auto complete for date fields +- new hook pageNavigationBar in bootstrap, preContent, postContent in ViewDocument +- major update of italian translation + +-------------------------------------------------------------------------------- + Changes in version 5.1.12 +-------------------------------------------------------------------------------- +- fix for CVE-2019-12932 (Persistent or Stored XSS), excaping the search + result in the autocompletion search form placed in the header +- fix more XSS problems on ViewDocument page +- folder/document list can be sorted by name, date, sequence (ascending or descending) +- search result can be sorted by name, date (ascending or descending) +- do not check for Log.php during installation anymore, it's part of the + vendor directory anyway +- fix uploading documents from drop folder +- replace placeholders in email body header and footer +- SeedDMS_EmailNotify::toIndividual() can send attachments +- fix for searching a document with the same name, which sometimes found a duplicate + name even if it didn't exist +- add config option for checking of duplicate subfolder names in the same folder +- rest api also checks for duplicate folder/document names if turned on +- before moving a document/folder the target folder is checked for an object with + the same name, if this is turned on in the configuration +- new controller EmptyFolder (currently not used) +- check for duplicate mails to the same group when a workflow was triggered +- new hook to output clipboard items +- turn on load on demand again in the folder tree + +-------------------------------------------------------------------------------- + Changes in version 5.1.11 +-------------------------------------------------------------------------------- +- fix for CVE-2019-12744 (Remote Command Execution through unvalidated + file upload), add .htaccess file to data directory, better documentation + for installing seeddms +- fix for CVE-2019-12745 (Persistent or Stored XSS in UsrMgr) and + CVE-2019-12801 (Persistent or Stored XSS in GroupMgr), propperly escape + strings used in Select2 js library used by UsrMgr and GroupMgr +- do not show attributes in search results in extra column anymore +- fix setting language during login (Closes #437) +- fix indexing documents even if no preIndexDocument hook is set (Closes #437) +- fix moving documents on the clipboard into the current folder +- new hook 'footNote' in class Bootstrap + -------------------------------------------------------------------------------- Changes in version 5.1.10 -------------------------------------------------------------------------------- @@ -150,6 +265,8 @@ via restapi - add an input field on the substitute user and extension list page for filtering table rows by string +- do not list users/groups in select menu on DocumentAccess page which already + has an access right -------------------------------------------------------------------------------- Changes in version 5.1.9 diff --git a/SeedDMS_Core/Core.php b/SeedDMS_Core/Core.php index 0f7b956ea..8a068e295 100644 --- a/SeedDMS_Core/Core.php +++ b/SeedDMS_Core/Core.php @@ -26,6 +26,11 @@ else */ require_once('Core/inc.ClassDMS.php'); +/** + * @uses SeedDMS_Decorator + */ +require_once('Core/inc.ClassDecorator.php'); + /** * @uses SeedDMS_Object */ @@ -96,4 +101,8 @@ require_once('Core/inc.FileUtils.php'); */ require_once('Core/inc.ClassTransmittal.php'); +/** + * @uses SeedDMS_File + */ +require_once('Core/inc.ClassIterator.php'); ?> diff --git a/SeedDMS_Core/Core/inc.ClassDMS.php b/SeedDMS_Core/Core/inc.ClassDMS.php index 31d05238c..76e4bee99 100644 --- a/SeedDMS_Core/Core/inc.ClassDMS.php +++ b/SeedDMS_Core/Core/inc.ClassDMS.php @@ -87,6 +87,13 @@ class SeedDMS_Core_DMS { */ protected $classnames; + /** + * @var array $decorators list of decorators for objects being instanciate + * by the dms + * @access protected + */ + protected $decorators; + /** * @var SeedDMS_Core_User $user reference to currently logged in user. This must be * an instance of {@link SeedDMS_Core_User}. This variable is currently not @@ -272,7 +279,7 @@ class SeedDMS_Core_DMS { $newArr = array(); foreach ($objArr as $obj) { if ($obj->getAccessMode($user) >= $minMode) { - $dms = $obj->_dms; + $dms = $obj->getDMS(); if(get_class($obj) == $dms->getClassname('document')) { if($obj->getLatestContent()) array_push($newArr, $obj); @@ -454,20 +461,20 @@ class SeedDMS_Core_DMS { $this->callbacks = array(); $this->version = '@package_version@'; if($this->version[0] == '@') - $this->version = '6.0.7'; + $this->version = '6.0.9'; } /* }}} */ /** - * Return class name of instantiated objects + * Return class name of classes instanciated by SeedDMS_Core * * This method returns the class name of those objects being instantiated * by the dms. Each class has an internal place holder, which must be * passed to function. * * @param string $objectname placeholder (can be one of 'folder', 'document', - * 'documentcontent', 'user', 'group' + * 'documentcontent', 'user', 'group') * - * @return string/boolean name of class or false if placeholder is invalid + * @return string/boolean name of class or false if object name is invalid */ function getClassname($objectname) { /* {{{ */ if(isset($this->classnames[$objectname])) @@ -499,6 +506,44 @@ class SeedDMS_Core_DMS { return $oldclass; } /* }}} */ + /** + * Return list of decorators + * + * This method returns the list of decorator class names of those objects + * being instantiated + * by the dms. Each class has an internal place holder, which must be + * passed to function. + * + * @param string $objectname placeholder (can be one of 'folder', 'document', + * 'documentcontent', 'user', 'group') + * + * @return array/boolean list of class names or false if object name is invalid + */ + function getDecorators($objectname) { /* {{{ */ + if(isset($this->decorators[$objectname])) + return $this->decorators[$objectname]; + else + return false; + } /* }}} */ + + /** + * Add a decorator + * + * This method adds a single decorator class name to the list of decorators + * of those objects being instantiated + * by the dms. Each class has an internal place holder, which must be + * passed to function. + * + * @param string $objectname placeholder (can be one of 'folder', 'document', + * 'documentcontent', 'user', 'group') + * + * @return boolean true if decorator could be added, otherwise false + */ + function addDecorator($objectname, $decorator) { /* {{{ */ + $this->decorators[$objectname][] = $decorator; + return true; + } /* }}} */ + /** * Return database where meta data is stored * @@ -1333,7 +1378,7 @@ class SeedDMS_Core_DMS { } } break; // }}} - case 'ReviseByMe': // Documents I have to receipt {{{ + case 'ReviseByMe': // Documents I have to revise {{{ if (!$this->db->createTemporaryTable("ttrevisionid")) { return false; } @@ -1405,6 +1450,27 @@ class SeedDMS_Core_DMS { } } break; // }}} + case 'DueRevision': // Documents with a due revision, which is not started {{{ + if (!$this->db->createTemporaryTable("ttrevisionid")) { + return false; + } + $user = $param1; + $orderby = $param3; + if($param4 == 'desc') + $orderdir = 'DESC'; + else + $orderdir = 'ASC'; + + $selectStr .= ", `tblDocumentContent`.`revisiondate` "; + $queryStr .= "WHERE `tblDocumentContent`.`revisiondate` IS NOT NULL AND `tblDocumentContent`.`revisiondate` <= ".$this->db->getCurrentDatetime()." "; + $queryStr .= "AND `tblDocumentStatusLog`.`status` = ".S_RELEASED." "; + if ($orderby=='e') $queryStr .= "ORDER BY `expires`"; + else if ($orderby=='u') $queryStr .= "ORDER BY `statusDate`"; + else if ($orderby=='s') $queryStr .= "ORDER BY `status`"; + else $queryStr .= "ORDER BY `name`"; + $queryStr .= " ".$orderdir; + $queryStr .= ", `tblDocumentContent`.`revisiondate` ASC"; + break; // }}} case 'WorkflowByMe': // Documents I to trigger in Worklflow {{{ $queryStr .= "WHERE 1=1 "; @@ -1812,6 +1878,14 @@ class SeedDMS_Core_DMS { * @return array|bool */ function search($query, $limit=0, $offset=0, $logicalmode='AND', $searchin=array(), $startFolder=null, $owner=null, $status = array(), $creationstartdate=array(), $creationenddate=array(), $modificationstartdate=array(), $modificationenddate=array(), $categories=array(), $attributes=array(), $mode=0x3, $expirationstartdate=array(), $expirationenddate=array(), $reception=array()) { /* {{{ */ + $orderby = ''; + if(is_array($query)) { + foreach(array('limit', 'offset', 'logicalmode', 'searchin', 'startFolder', 'owner', 'status', 'creationstartdate', 'creationenddate', 'modificationstartdate', 'modificationenddate', 'categories', 'attributes', 'mode', 'expirationstartdate', 'expirationenddate', 'reception') as $paramname) + ${$paramname} = isset($query[$paramname]) ? $query[$paramname] : ${$paramname}; + foreach(array('orderby') as $paramname) + ${$paramname} = isset($query[$paramname]) ? $query[$paramname] : ''; + $query = isset($query['query']) ? $query['query'] : ''; + } // Split the search string into constituent keywords. $tkeys=array(); if (strlen($query)>0) { @@ -1938,6 +2012,23 @@ class SeedDMS_Core_DMS { // Prepare the complete search query, including the LIMIT clause. $searchQuery = "SELECT DISTINCT `tblFolders`.`id` ".$searchQuery." GROUP BY `tblFolders`.`id`"; + switch($orderby) { + case 'dd': + $searchQuery .= " ORDER BY `tblFolders`.`date` DESC"; + break; + case 'da': + case 'd': + $searchQuery .= " ORDER BY `tblFolders`.`date`"; + break; + case 'nd': + $searchQuery .= " ORDER BY `tblFolders`.`name` DESC"; + break; + case 'na': + default: + $searchQuery .= " ORDER BY `tblFolders`.`name`"; + break; + } + if($limit) { $searchQuery .= " LIMIT ".$limit." OFFSET ".$offset; } @@ -2198,6 +2289,23 @@ class SeedDMS_Core_DMS { "`tblDocumentContent`.`version`, ". "`tblDocumentStatusLog`.`status`, `tblDocumentLocks`.`userID` as `lockUser` ".$searchQuery; + switch($orderby) { + case 'dd': + $orderbyQuery = " ORDER BY `tblDocuments`.`date` DESC"; + break; + case 'da': + case 'd': + $orderbyQuery = " ORDER BY `tblDocuments`.`date`"; + break; + case 'nd': + $orderbyQuery = " ORDER BY `tblDocuments`.`name` DESC"; + break; + case 'na': + default: + $orderbyQuery = " ORDER BY `tblDocuments`.`name`"; + break; + } + // calculate the remaining entrїes of the current page // If page is not full yet, get remaining entries if($limit) { @@ -2207,6 +2315,9 @@ class SeedDMS_Core_DMS { $offset -= $totalFolders; else $offset = 0; + + $searchQuery .= $orderbyQuery; + if($limit) $searchQuery .= " LIMIT ".$limit." OFFSET ".$offset; @@ -2218,11 +2329,13 @@ class SeedDMS_Core_DMS { $resArr = array(); } } else { + $searchQuery .= $orderbyQuery; + // Send the complete search query to the database. $resArr = $this->db->getResultArray($searchQuery); if($resArr === false) return false; - } + } // ------------------- Ausgabe der Ergebnisse ---------------------------- $numResults = count($resArr); @@ -3518,6 +3631,46 @@ class SeedDMS_Core_DMS { } /* }}} */ + /** + * Returns document content which has the incorrect file type + * + * This method is for finding document content with an incorrect + * or missing file type. It just checks documents contents + * with a certain mime type. + * @return bool|SeedDMS_Core_Document[] + */ + function getWrongFiletypeDocumentContent() { /* {{{ */ + $queryStr = "SELECT * FROM `tblDocumentContent` WHERE `mimeType` in ('application/pdf', 'image/png', 'image/gif', 'image/jpg')"; + $resArr = $this->db->getResultArray($queryStr); + if ($resArr === false) + return false; + + /** @var SeedDMS_Core_Document[] $versions */ + $versions = array(); + foreach($resArr as $row) { + $expect = ''; + switch($row['mimeType']) { + case "application/pdf": + case "image/png": + case "image/gif": + case "image/jpg": + $expect = substr($row['mimeType'], -3, 3); + break; + } + if($expect) { + if($row['fileType'] != '.'.$expect) { + /** @var SeedDMS_Core_Document $document */ + $document = new $this->classnames['document']($row['document'], '', '', '', '', '', '', '', '', '', '', ''); + $document->setDMS($this); + $version = new $this->classnames['documentcontent']($row['id'], $document, $row['version'], $row['comment'], $row['date'], $row['createdBy'], $row['dir'], $row['orgFileName'], $row['fileType'], $row['mimeType'], $row['fileSize'], $row['checksum']); + $versions[] = $version; + } + } + } + return $versions; + + } /* }}} */ + /** * Returns document content which is duplicated * diff --git a/SeedDMS_Core/Core/inc.ClassDecorator.php b/SeedDMS_Core/Core/inc.ClassDecorator.php new file mode 100644 index 000000000..9450d5fef --- /dev/null +++ b/SeedDMS_Core/Core/inc.ClassDecorator.php @@ -0,0 +1,42 @@ + + * @copyright Copyright (C) 2010, Uwe Steinmann + * @version Release: @package_version@ + */ + + +/** + * Class which implements a simple decorator pattern + * + * @category DMS + * @package SeedDMS_Core + * @version @version@ + * @author Uwe Steinmann + * @copyright Copyright (C) 2010, Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_Core_Decorator { + protected $o; + + public function __construct($object) { + $this->o = $object; + } + + public function __call($method, $args) + { + if (!method_exists($this->o, $method)) { + throw new Exception("Undefined method $method attempt."); + } + /* In case the called method returns the object itself, then return this object */ + $result = call_user_func_array(array($this->o, $method), $args); + return $result === $this->o ? $this : $result; + } +} + diff --git a/SeedDMS_Core/Core/inc.ClassDocument.php b/SeedDMS_Core/Core/inc.ClassDocument.php index 35b8ed9f9..bc30ce62c 100644 --- a/SeedDMS_Core/Core/inc.ClassDocument.php +++ b/SeedDMS_Core/Core/inc.ClassDocument.php @@ -249,6 +249,15 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $this->_content = null; } /* }}} */ + /** + * Check if this object is of type 'document'. + * + * @param string $type type of object + */ + public function isType($type) { /* {{{ */ + return $type == 'document'; + } /* }}} */ + /** * Return an array of database fields which used for searching * a term entered in the database search form @@ -283,6 +292,22 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ return $searchFields; } /* }}} */ + /** + * Return a folder by its database record + * + * @param array $resArr array of folder data as returned by database + * @param SeedDMS_Core_DMS $dms + * @return SeedDMS_Core_Folder|bool instance of SeedDMS_Core_Folder if document exists + */ + public static function getInstanceByData($resArr, $dms) { /* {{{ */ + $classname = $dms->getClassname('document'); + /** @var SeedDMS_Core_Document $document */ + $document = new $classname($resArr["id"], $resArr["name"], $resArr["comment"], $resArr["date"], $resArr["expires"], $resArr["owner"], $resArr["folder"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr['lock'], $resArr["keywords"], $resArr["sequence"]); + $document->setDMS($dms); + $document = $document->applyDecorators(); + return $document; + } /* }}} */ + /** * Return an document by its id * @@ -294,7 +319,8 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ public static function getInstance($id, $dms) { /* {{{ */ $db = $dms->getDB(); - $queryStr = "SELECT * FROM `tblDocuments` WHERE `id` = " . (int) $id; +// $queryStr = "SELECT * FROM `tblDocuments` WHERE `id` = " . (int) $id; + $queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lock` FROM `tblDocuments` LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id` = `tblDocumentLocks`.`document` WHERE `id` = " . (int) $id; $resArr = $db->getResultArray($queryStr); if (is_bool($resArr) && $resArr == false) return false; @@ -303,24 +329,48 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $resArr = $resArr[0]; // New Locking mechanism uses a separate table to track the lock. + /* $queryStr = "SELECT * FROM `tblDocumentLocks` WHERE `document` = " . (int) $id; $lockArr = $db->getResultArray($queryStr); if ((is_bool($lockArr) && $lockArr==false) || (count($lockArr)==0)) { // Could not find a lock on the selected document. - $lock = -1; + $resArr['lock'] = -1; } else { // A lock has been identified for this document. - $lock = $lockArr[0]["userID"]; + $resArr['lock'] = $lockArr[0]["userID"]; } +*/ + $resArr['lock'] = !$resArr['lock'] ? -1 : $resArr['lock']; +// print_r($resArr);exit; + + return self::getInstanceByData($resArr, $dms); $classname = $dms->getClassname('document'); /** @var SeedDMS_Core_Document $document */ - $document = new $classname($resArr["id"], $resArr["name"], $resArr["comment"], $resArr["date"], $resArr["expires"], $resArr["owner"], $resArr["folder"], $resArr["inheritAccess"], $resArr["defaultAccess"], $lock, $resArr["keywords"], $resArr["sequence"]); + $document = new $classname($resArr["id"], $resArr["name"], $resArr["comment"], $resArr["date"], $resArr["expires"], $resArr["owner"], $resArr["folder"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr['lock'], $resArr["keywords"], $resArr["sequence"]); $document->setDMS($dms); + $document = $document->applyDecorators(); return $document; } /* }}} */ + /** + * Apply decorators + * + * @return object final object after all decorators has been applied + */ + function applyDecorators() { /* {{{ */ + if($decorators = $this->_dms->getDecorators('document')) { + $s = $this; + foreach($decorators as $decorator) { + $s = new $decorator($s); + } + return $s; + } else { + return $this; + } + } /* }}} */ + /** * Return the directory of the document in the file system relativ * to the contentDir @@ -468,7 +518,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $db = $this->_dms->getDB(); if(!$this->_categories) - self::getCategories(); + $this->getCategories(); $catids = array(); foreach($this->_categories as $cat) @@ -546,13 +596,31 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ return true; } /* }}} */ + /** + * Check, if this document is below of a given folder + * + * @param object $folder parent folder + * @return boolean true if folder is a subfolder + */ + function isDescendant($folder) { /* {{{ */ + /* First check if the parent folder is folder looking for */ + if ($this->getFolder()->getID() == $folder->getID()) + return true; + /* Second, check for the parent folder of this document to be + * below the given folder + */ + if($this->getFolder()->isDescendant($folder)) + return true; + return false; + } /* }}} */ + /** * Return the parent folder of the document * * @return SeedDMS_Core_Folder parent folder */ function getParent() { /* {{{ */ - return self::getFolder(); + return $this->getFolder(); } /* }}} */ function getFolder() { /* {{{ */ @@ -681,7 +749,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $this->_defaultAccess = $mode; if(!$noclean) - self::cleanNotifyList(); + $this->cleanNotifyList(); return true; } /* }}} */ @@ -715,7 +783,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $this->_inheritAccess = ($inheritAccess ? "1" : "0"); if(!$noclean) - self::cleanNotifyList(); + $this->cleanNotifyList(); return true; } /* }}} */ @@ -808,7 +876,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ /** - * Check if latest content of the document has a schedult + * Check if latest content of the document has a scheduled * revision workflow. * The method will update the document status log database table * if needed. @@ -825,8 +893,9 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ if($lc) { $st=$lc->getStatus(); + /* A revision workflow will only be started if the document is released */ if($st["status"] == S_RELEASED) { - /* First check if there are any revisors left who need to revise */ + /* First check if there are any scheduled revisions currently sleeping */ $pendingRevision=false; unset($this->_revisionStatus); // force to be reloaded from DB $revisionStatus=$lc->getRevisionStatus(); @@ -841,7 +910,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ if(!$pendingRevision) return false; - /* Second check if revision is already due */ + /* We have sleeping revision, next check if the revision is already due */ if($lc->getRevisionDate() && $lc->getRevisionDate() <= date('Y-m-d 00:00:00')) { if($lc->startRevision($user, 'Automatic start of revision workflow')) { if($next) { @@ -1163,7 +1232,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ unset($this->_accessList); if(!$noclean) - self::cleanNotifyList(); + $this->cleanNotifyList(); return true; } /* }}} */ @@ -1750,6 +1819,8 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $version = $resArr[0]['m']+1; } + if($fileType == '.') + $fileType = ''; $filesize = SeedDMS_Core_File::fileSize($tmpFile); $checksum = SeedDMS_Core_File::checksum($tmpFile); @@ -1922,7 +1993,10 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ if(!$content) return false; - /* Check if $user, $orgFileName, $fileType and $mimetype are the same */ + if($fileType == '.') + $fileType = ''; + + /* Check if $user, $orgFileName, $fileType and $mimeType are the same */ if($user->getID() != $content->getUser()->getID()) { return false; } @@ -2123,7 +2197,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $status = $version->getStatus(); $stID = $status["statusID"]; - $queryStr = "DELETE FROM `tblDocumentContent` WHERE `document` = " . $this->getID() . " AND `version` = " . $version->_version; + $queryStr = "DELETE FROM `tblDocumentContent` WHERE `document` = " . $this->getID() . " AND `version` = " . $version->getVersion(); if (!$db->getResult($queryStr)) { $db->rollbackTransaction(); return false; @@ -2135,7 +2209,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ return false; } - $queryStr = "DELETE FROM `tblTransmittalItems` WHERE `document` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "DELETE FROM `tblTransmittalItems` WHERE `document` = '". $this->getID() ."' AND `version` = '" . $version->getVersion()."'"; if (!$db->getResult($queryStr)) { $db->rollbackTransaction(); return false; @@ -2147,7 +2221,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ return false; } - $queryStr = "DELETE FROM `tblDocumentStatus` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "DELETE FROM `tblDocumentStatus` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->getVersion()."'"; if (!$db->getResult($queryStr)) { $db->rollbackTransaction(); return false; @@ -2177,7 +2251,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ return false; } } - $queryStr = "DELETE FROM `tblDocumentReviewers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "DELETE FROM `tblDocumentReviewers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->getVersion()."'"; if (!$db->getResult($queryStr)) { $db->rollbackTransaction(); return false; @@ -2206,7 +2280,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ return false; } } - $queryStr = "DELETE FROM `tblDocumentApprovers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "DELETE FROM `tblDocumentApprovers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->getVersion()."'"; if (!$db->getResult($queryStr)) { $db->rollbackTransaction(); return false; @@ -2216,7 +2290,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ * This implmentation is different from the above for removing approvals * and reviews. It doesn't use getReceiptStatus() but reads the database */ - $queryStr = "SELECT * FROM `tblDocumentRecipients` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "SELECT * FROM `tblDocumentRecipients` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->getVersion()."'"; $resArr = $db->getResultArray($queryStr); if ((is_bool($resArr) && !$resArr)) { $db->rollbackTransaction(); @@ -2245,7 +2319,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ * This implementation is different from the above for removing approvals * and reviews. It doesn't use getRevisionStatus() but reads the database */ - $queryStr = "SELECT * FROM `tblDocumentRevisors` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "SELECT * FROM `tblDocumentRevisors` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->getVersion()."'"; $resArr = $db->getResultArray($queryStr); if ((is_bool($resArr) && !$resArr)) { $db->rollbackTransaction(); @@ -2270,7 +2344,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ } } - $queryStr = "DELETE FROM `tblWorkflowDocumentContent` WHERE `document` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "DELETE FROM `tblWorkflowDocumentContent` WHERE `document` = '". $this->getID() ."' AND `version` = '" . $version->getVersion()."'"; if (!$db->getResult($queryStr)) { $db->rollbackTransaction(); return false; @@ -2278,7 +2352,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ /* Will be deleted automatically when record will be deleted * from tblWorkflowDocumentContent - $queryStr = "DELETE FROM `tblWorkflowLog` WHERE `document` = '". $this->getID() ."' AND `version` = '" . $version->_version."'"; + $queryStr = "DELETE FROM `tblWorkflowLog` WHERE `document` = '". $this->getID() ."' AND `version` = '" . $version->getVersion."'"; if (!$db->getResult($queryStr)) { $db->rollbackTransaction(); return false; @@ -2286,7 +2360,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ */ // remove document files attached to version - $res = $this->getDocumentFiles($version->_version); + $res = $this->getDocumentFiles($version->getVersion()); if (is_bool($res) && !$res) { $db->rollbackTransaction(); return false; @@ -2918,7 +2992,8 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $timeline = array(); - $queryStr = "SELECT `revisiondate`, `version` FROM `tblDocumentContent` WHERE `document` = " . $this->_id; + $lc=$this->getLatestContent(); + $queryStr = "SELECT `revisiondate`, `version` FROM `tblDocumentContent` WHERE `document` = " . $this->_id . " AND `version` = " . $lc->getVersion(); $resArr = $db->getResultArray($queryStr); if (is_bool($resArr) && $resArr == false) return false; @@ -3032,41 +3107,129 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ * @version Release: @package_version@ */ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ + /** + * @var object document + */ + protected $_document; + + /** + * @var integer version + */ + protected $_version; + + /** + * @var string comment + */ + protected $_comment; + + /** + * @var string date + */ + protected $_date; + + /** + * @var integer userID + */ + protected $_userID; + + /** + * @var string dir on disk (deprecated) + */ + protected $_dir; + + /** + * @var string original file name + */ + protected $_orgFileName; + + /** + * @var string file type (actually the extension without the leading dot) + */ + protected $_fileType; + + /** + * @var string mime type + */ + protected $_mimeType; + + /** + * @var string checksum of content + */ + protected $_checksum; + + /** + * @var object workflow + */ + protected $_workflow; + + /** + * @var object workflow state + */ + protected $_workflowState; + + /** + * @var object dms + */ + public $_dms; /** * Recalculate the status of a document + * * The methods checks the review and approval status and sets the * status of the document accordingly. - * If status is S_RELEASED and version has workflow set status - * to S_IN_WORKFLOW - * If status is S_RELEASED and there are reviewers set status S_DRAFT_REV - * If status is S_RELEASED or S_DRAFT_REV and there are approvers set + * + * If status is S_RELEASED and the version has a workflow, then set + * the status to S_IN_WORKFLOW + * If status is S_RELEASED and there are reviewers => set status S_DRAFT_REV + * If status is S_RELEASED or S_DRAFT_REV and there are approvers => set * status S_DRAFT_APP - * If status is draft and there are no approver and no reviewers set + * If status is draft and there are no approver and no reviewers => set * status to S_RELEASED * The status of a document with the current status S_OBSOLETE, S_REJECTED, - * or S_EXPIRED will not be changed unless the parameter + * S_NEEDS_CORRECTION or S_EXPIRED will not be changed unless the parameter * $ignorecurrentstatus is set to true. + * + * This method may not be called after a negative approval or review to + * recalculated the status, because + * it doesn't take a defeating approval or review into account. This method + * does not set the status to S_REJECTED! It will + * just check for a pending workflow, approval or review and set the status + * accordingly, e.g. after the list of reviewers or appovers has been + * modified. If there is not pending workflow, approval or review the + * status will be set to S_RELEASED. + * * This method will call {@see SeedDMS_Core_DocumentContent::setStatus()} - * which checks if the state has actually changed. This is, why this + * which checks if the status has actually changed. This is, why this * function can be called at any time without harm to the status log. + * The $initialstatus can be set, to define the status set when no other + * status is set. This happens if the document has no * * @param boolean $ignorecurrentstatus ignore the current status and * recalculate a new status in any case * @param object $user the user initiating this method * @param string $msg message stored in status log when status is set + * @param integer $initialstatus status to be set if no other status is set */ - function verifyStatus($ignorecurrentstatus=false, $user=null, $msg='') { /* {{{ */ + function verifyStatus($ignorecurrentstatus=false, $user=null, $msg='', $initialstatus=S_RELEASED) { /* {{{ */ unset($this->_status); $st=$this->getStatus(); - if (!$ignorecurrentstatus && ($st["status"]==S_OBSOLETE || $st["status"]==S_REJECTED || $st["status"]==S_EXPIRED )) return; + /* Documents already obsoleted, rejected or expired will not change + * its status anymore, unless explicitly requested. Be aware, that + * this method has an unsufficient check for negative reviews and + * approvals. A document in status S_REJECTED may become S_RELEASED + * if there is at least one positive review or approval. + */ + if (!$ignorecurrentstatus && ($st["status"]==S_OBSOLETE || $st["status"]==S_REJECTED || $st["status"]==S_EXPIRED || $st["status"]==S_NEEDS_CORRECTION)) return; unset($this->_workflow); // force to be reloaded from DB $hasworkflow = $this->getWorkflow() ? true : false; + /* $pendingReview will be set when there are still open reviews */ $pendingReview=false; + /* $hasReview will be set if there is at least one positiv review */ + $hasReview=false; unset($this->_reviewStatus); // force to be reloaded from DB $reviewStatus=$this->getReviewStatus(); if (is_array($reviewStatus) && count($reviewStatus)>0) { @@ -3074,10 +3237,16 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ if ($r["status"]==0){ $pendingReview=true; break; + } elseif($r["status"]==1){ + $hasReview=true; } } } + + /* $pendingApproval will be set when there are still open approvals */ $pendingApproval=false; + /* $hasApproval will be set if there is at least one positiv review */ + $hasApproval=false; unset($this->_approvalStatus); // force to be reloaded from DB $approvalStatus=$this->getApprovalStatus(); if (is_array($approvalStatus) && count($approvalStatus)>0) { @@ -3085,10 +3254,14 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ if ($a["status"]==0){ $pendingApproval=true; break; + } elseif($a["status"]==1){ + $hasApproval=true; } } } $pendingRevision=false; + $hasRevision=false; + $needsCorrection=false; unset($this->_revisionStatus); // force to be reloaded from DB $revsisionStatus=$this->getRevisionStatus(); if (is_array($revsisionStatus) && count($revsisionStatus)>0) { @@ -3096,16 +3269,51 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ if ($a["status"]==0){ $pendingRevision=true; break; + } elseif($a["status"]==1){ + $hasRevision=true; + } elseif($a["status"]==-1){ + $needsCorrection=true; } } } + /* First check for a running workflow or open reviews, approvals, revisions. */ if ($hasworkflow) $this->setStatus(S_IN_WORKFLOW,$msg,$user); elseif ($pendingReview) $this->setStatus(S_DRAFT_REV,$msg,$user); elseif ($pendingApproval) $this->setStatus(S_DRAFT_APP,$msg,$user); elseif ($pendingRevision) $this->setStatus(S_IN_REVISION,$msg,$user); - /* A document in status S_DRAFT will never go into S_RELEASED */ - elseif ($st["status"]!=S_DRAFT) $this->setStatus(S_RELEASED,$msg,$user); + /* This point will only be reached if there is no pending workflow, review, + * approval or revision but the current status is one of S_DRAFT_REV, + * S_DRAFT_APP or S_IN_REVISION. This can happen if formely set reviewers, + * approvers, revisors are completly removed. In case of S_DRAFT_REV and + * S_DRAFT_APP the document will go back into its initial status. If a + * positive review or approval was found the document will be released. + * Be aware that negative reviews or approvals are not taken into account, + * because in that case the document must have been rejected before calling + * this function. FIXME: this is a problem if the parameter $ignorecurrentstatus + * was set, because an already rejected document may be released with just + * one positive review or approval disregarding any negative reviews or + * approvals. + * A document in status S_IN_REVISION will be treated differently. + * It takes negative revisions into account! + * + * A document in status S_DRAFT will never go into S_RELEASED and document + * already released will never go back at this point into the given + * initial status, which can only by S_DRAFT or S_RELEASED + */ + elseif ($st["status"]!=S_DRAFT && $st["status"]!=S_RELEASED ) { + if($st["status"]==S_DRAFT_REV || $st["status"]==S_DRAFT_APP) { + if($hasReview || $hasApproval) $this->setStatus(S_RELEASED,$msg,$user); + else $this->setStatus($initialstatus,$msg,$user); + } elseif($st["status"]==S_IN_REVISION) { + if($needsCorrection) $this->setStatus(S_NEEDS_CORRECTION,$msg,$user); + else $this->setStatus(S_RELEASED,$msg,$user); + } elseif($st["status"]==S_EXPIRED) { + $this->setStatus(S_RELEASED,$msg,$user); + } + + } + } /* }}} */ function __construct($id, $document, $version, $comment, $date, $userID, $dir, $orgFileName, $fileType, $mimeType, $fileSize=0, $checksum='', $revisionDate=null) { /* {{{ */ @@ -3119,7 +3327,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ $this->_orgFileName = $orgFileName; $this->_fileType = $fileType; $this->_mimeType = $mimeType; - $this->_dms = $document->_dms; + $this->_dms = $document->getDMS(); if(!$fileSize) { $this->_fileSize = SeedDMS_Core_File::fileSize($this->_dms->contentDir . $this->getPath()); } else { @@ -3165,27 +3373,48 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ return null; } /* }}} */ + /** + * Check if this object is of type 'documentcontent'. + * + * @param string $type type of object + */ + public function isType($type) { /* {{{ */ + return $type == 'documentcontent'; + } /* }}} */ + function getVersion() { return $this->_version; } function getComment() { return $this->_comment; } function getDate() { return $this->_date; } function getOriginalFileName() { return $this->_orgFileName; } function getFileType() { return $this->_fileType; } function getFileName(){ return $this->_version . $this->_fileType; } - function getDir() { return $this->_dir; } + /** + * getDir and the corresponding database table field are deprecated + */ + function __getDir() { return $this->_dir; } function getMimeType() { return $this->_mimeType; } function getRevisionDate() { return $this->_revisionDate; } function getDocument() { return $this->_document; } function getUser() { /* {{{ */ if (!isset($this->_user)) - $this->_user = $this->_document->_dms->getUser($this->_userID); + $this->_user = $this->_document->getDMS()->getUser($this->_userID); return $this->_user; } /* }}} */ + /** + * Return path of file on disk relative to the content directory + * + * Since version 5.1.13 a single '.' in the fileType will be skipped. + * On Windows a file named 'name.' will be saved as 'name' but the fileType + * will contain the a single '.'. + * + * @return string path of file on disc + */ function getPath() { return $this->_document->getDir() . $this->_version . $this->_fileType; } function setRevisionDate($date = false) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$date) $queryStr = "UPDATE `tblDocumentContent` SET `revisiondate` = null WHERE `document` = " . $this->_document->getID() . " AND `version` = " . $this->_version; @@ -3202,7 +3431,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function setDate($date = false) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$date) $date = time(); @@ -3232,7 +3461,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ if($filesize === false) return false; - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr = "UPDATE `tblDocumentContent` SET `fileSize` = ".$filesize." where `document` = " . $this->_document->getID() . " AND `version` = " . $this->_version; if (!$db->getResult($queryStr)) return false; @@ -3253,7 +3482,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ if($checksum === false) return false; - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr = "UPDATE `tblDocumentContent` SET `checksum` = ".$db->qstr($checksum)." where `document` = " . $this->_document->getID() . " AND `version` = " . $this->_version; if (!$db->getResult($queryStr)) return false; @@ -3262,8 +3491,42 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ return true; } /* }}} */ + /** + * Set file type by evaluating the mime type + */ + function setFileType() { /* {{{ */ + $mimetype = $this->getMimeType(); + + switch($this->_mimeType) { + case "application/pdf": + case "image/png": + case "image/gif": + case "image/jpg": + $expect = substr($this->_mimeType, -3, 3); + break; + } + if($expect && '.'.$expect != $this->_fileType) { + $db = $this->_document->getDMS()->getDB(); + $db->startTransaction(); + $queryStr = "UPDATE `tblDocumentContent` SET `fileType`='.".$expect."' WHERE `id` = ". $this->_id; + $res = $db->getResult($queryStr); + if ($res) { + if(!SeedDMS_Core_File::renameFile($this->_dms->contentDir.$this->_document->getDir() . $this->_version . $this->_fileType, $this->_dms->contentDir.$this->_document->getDir() . $this->_version . '.' . $expect)) { + $db->rollbackTransaction(); + } else { + $db->commitTransaction(); + return true; + } + } else { + $db->rollbackTransaction(); + } + } + + return false; + } /* }}} */ + function setComment($newComment) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr = "UPDATE `tblDocumentContent` SET `comment` = ".$db->qstr($newComment)." WHERE `document` = " . $this->_document->getID() . " AND `version` = " . $this->_version; if (!$db->getResult($queryStr)) @@ -3297,8 +3560,10 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * * @return array latest record from tblDocumentStatusLog */ - function getStatus() { /* {{{ */ - $db = $this->_document->_dms->getDB(); + function getStatus($limit=1) { /* {{{ */ + $db = $this->_document->getDMS()->getDB(); + + if (!is_numeric($limit)) return false; // Retrieve the current overall status of the content represented by // this object. @@ -3311,7 +3576,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ "LEFT JOIN `tblDocumentStatusLog` USING (`statusID`) ". "WHERE `tblDocumentStatus`.`documentID` = '". $this->_document->getID() ."' ". "AND `tblDocumentStatus`.`version` = '". $this->_version ."' ". - "ORDER BY `tblDocumentStatusLog`.`statusLogID` DESC LIMIT 1"; + "ORDER BY `tblDocumentStatusLog`.`statusLogID` DESC LIMIT ".(int) $limit; $res = $db->getResultArray($queryStr); if (is_bool($res) && !$res) @@ -3330,7 +3595,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return array list of status changes */ function getStatusLog($limit=0) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if (!is_numeric($limit)) return false; @@ -3365,7 +3630,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return boolean true on success, otherwise false */ function setStatus($status, $comment, $updateUser, $date='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if (!is_numeric($status)) return false; @@ -3397,6 +3662,15 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ if (is_bool($res) && !$res) return false; + /* Check if 'onSetStatus' callback is set */ + if(isset($this->_dms->callbacks['onSetStatus'])) { + foreach($this->_dms->callbacks['onSetStatus'] as $callback) { + $ret = call_user_func($callback[0], $callback[1], $this, $this->_status["status"], $status); + if(is_bool($ret)) + return $ret; + } + } + unset($this->_status); return true; } /* }}} */ @@ -3412,7 +3686,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return boolean true on success, otherwise false */ function rewriteStatusLog($statuslog) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr= "SELECT `tblDocumentStatus`.* FROM `tblDocumentStatus` WHERE `tblDocumentStatus`.`documentID` = '". $this->_document->getID() ."' AND `tblDocumentStatus`.`version` = '". $this->_version ."' "; $res = $db->getResultArray($queryStr); @@ -3471,7 +3745,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return integer either M_NONE or M_READ */ function getAccessMode($u) { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); /* Check if 'onCheckAccessDocumentContent' callback is set */ if(isset($this->_dms->callbacks['onCheckAccessDocumentContent'])) { @@ -3603,7 +3877,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return array list of review status */ function getReviewStatus($limit=1) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if (!is_numeric($limit)) return false; @@ -3663,7 +3937,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return boolean true on success, otherwise false */ function rewriteReviewLog($reviewers) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr= "SELECT `tblDocumentReviewers`.* FROM `tblDocumentReviewers` WHERE `tblDocumentReviewers`.`documentID` = '". $this->_document->getID() ."' AND `tblDocumentReviewers`.`version` = '". $this->_version ."' "; $res = $db->getResultArray($queryStr); @@ -3731,7 +4005,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return array list of approval status */ function getApprovalStatus($limit=1) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if (!is_numeric($limit)) return false; @@ -3791,7 +4065,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return boolean true on success, otherwise false */ function rewriteApprovalLog($reviewers) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr= "SELECT `tblDocumentApprovers`.* FROM `tblDocumentApprovers` WHERE `tblDocumentApprovers`.`documentID` = '". $this->_document->getID() ."' AND `tblDocumentApprovers`.`version` = '". $this->_version ."' "; $res = $db->getResultArray($queryStr); @@ -3859,7 +4133,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return array list of receipts */ function getReceiptStatus($limit=1) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if (!is_numeric($limit)) return false; @@ -3935,7 +4209,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return boolean true on success, otherwise false */ function rewriteReceiptLog($recipients) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr= "SELECT `tblDocumentRecipients`.* FROM `tblDocumentRecipients` WHERE `tblDocumentRecipients`.`documentID` = '". $this->_document->getID() ."' AND `tblDocumentRecipients`.`version` = '". $this->_version ."' "; $res = $db->getResultArray($queryStr); @@ -4003,7 +4277,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return array list of revisions */ function getRevisionStatus($limit=1) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if (!is_numeric($limit)) return false; @@ -4055,10 +4329,10 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * This method was added for importing an xml dump. * * @param array $revisionlog new status log with the newest log entry first. - * @return boolean true on success, otherwise false + * @return boolean 0 on success, otherwise a negativ error number */ function rewriteRevisionLog($revisions) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr= "SELECT `tblDocumentRevisors`.* FROM `tblDocumentRevisors` WHERE `tblDocumentRevisors`.`documentID` = '". $this->_document->getID() ."' AND `tblDocumentRevisors`.`version` = '". $this->_version ."' "; $res = $db->getResultArray($queryStr); @@ -4119,7 +4393,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function addIndReviewer($user, $requestUser) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $userID = $user->getID(); @@ -4170,7 +4444,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function addGrpReviewer($group, $requestUser) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $groupID = $group->getID(); @@ -4248,7 +4522,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return integer new review log id */ function setReviewByInd($user, $requestUser, $status, $comment, $file='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); // Check to see if the user can be removed from the review list. $reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version); @@ -4300,7 +4574,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return integer new review log id */ function setReviewByGrp($group, $requestUser, $status, $comment, $file='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); // Check to see if the user can be removed from the review list. $reviewStatus = $group->getReviewStatus($this->_document->getID(), $this->_version); @@ -4339,7 +4613,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function addIndApprover($user, $requestUser) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $userID = $user->getID(); @@ -4388,7 +4662,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function addGrpApprover($group, $requestUser) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $groupID = $group->getID(); @@ -4470,7 +4744,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return integer 0 on success, < 0 in case of an error */ function setApprovalByInd($user, $requestUser, $status, $comment, $file='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); // Check to see if the user can be removed from the approval list. $approvalStatus = $user->getApprovalStatus($this->_document->getID(), $this->_version); @@ -4514,7 +4788,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * group instead of a user */ function setApprovalByGrp($group, $requestUser, $status, $comment, $file='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); // Check to see if the user can be removed from the approval list. $approvalStatus = $group->getApprovalStatus($this->_document->getID(), $this->_version); @@ -4552,7 +4826,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function addIndRecipient($user, $requestUser) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $userID = $user->getID(); @@ -4603,7 +4877,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function addGrpRecipient($group, $requestUser) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $groupID = $group->getID(); @@ -4676,7 +4950,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return integer 0 if successful otherwise a value < 0 */ function addRevisor($object, $requestUser) { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); $db = $dms->getDB(); /* getRevisionStatus() returns an array with either an element @@ -4785,7 +5059,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return integer new receipt log id */ function setReceiptByInd($user, $requestUser, $status, $comment) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); // Check to see if the user can be removed from the review list. $receiptStatus = $user->getReceiptStatus($this->_document->getID(), $this->_version); @@ -4833,7 +5107,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return integer new receipt log id */ function setReceiptByGrp($group, $requestUser, $status, $comment) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); // Check to see if the user can be removed from the recipient list. $receiptStatus = $group->getReceiptStatus($this->_document->getID(), $this->_version); @@ -4899,7 +5173,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * -5: the revision has not been started at all. */ function setRevision($object, $requestUser, $status, $comment) { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); $db = $dms->getDB(); /* getRevisionStatus() returns an array with either an element @@ -4960,7 +5234,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function delIndReviewer($user, $requestUser, $msg='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); // Check to see if the user can be removed from the review list. $reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version); @@ -4990,7 +5264,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function delGrpReviewer($group, $requestUser, $msg='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $groupID = $group->getID(); @@ -5021,7 +5295,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function delIndApprover($user, $requestUser, $msg='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $userID = $user->getID(); @@ -5053,7 +5327,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function delGrpApprover($group, $requestUser, $msg='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $groupID = $group->getID(); @@ -5084,7 +5358,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function delIndRecipient($user, $requestUser, $msg='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $userID = $user->getID(); @@ -5116,7 +5390,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ } /* }}} */ function delGrpRecipient($group, $requestUser, $msg='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $groupID = $group->getID(); @@ -5166,7 +5440,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * */ function delRevisor($object, $requestUser, $msg='') { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); $db = $dms->getDB(); /* getRevisionStatus() returns an array with either an element @@ -5240,7 +5514,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @param string $msg message saved for the initial log message */ function startRevision($requestUser, $msg='') { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); $db = $dms->getDB(); $revisionStatus = self::getRevisionStatus(); @@ -5250,10 +5524,15 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ /* A new revision may only be started if we are not in the middle of * revision or the user/group has been removed from the workflow */ + /* Taken out, because it happened that a revision wasn't started for each revisor + * but just for some. + * Checking for each revisor not being sleeping prevented a second start of the + * revision for the remaining revisors still sleeping. foreach($revisionStatus as $status) { if($status['status'] != S_LOG_SLEEPING && $status['status'] != S_LOG_USER_REMOVED) return false; } + */ /* Make sure all Logs will be set to the right status, in order to * prevent inconsistent states. Actually it could be a feature to @@ -5261,6 +5540,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * this may not be possible. */ $db->startTransaction(); + $startedrev = false; foreach($revisionStatus as $status) { if($status['status'] == S_LOG_SLEEPING) { $queryStr = "INSERT INTO `tblDocumentRevisionLog` (`revisionID`, `status`, @@ -5273,12 +5553,15 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ $db->rollbackTransaction(); return false; } + $startedrev = true; } } - if(!$this->setStatus(S_IN_REVISION, "Started revision", $requestUser)) { - $db->rollbackTransaction(); - return false; - } + /* Set status only if at least one revision was started */ + if($startedrev) + if(!$this->setStatus(S_IN_REVISION, "Started revision", $requestUser)) { + $db->rollbackTransaction(); + return false; + } $db->commitTransaction(); return true; @@ -5298,7 +5581,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @param string $msg message saved in document status log */ function finishRevision($requestUser, $docstatus, $msg='', $docmsg='') { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); $db = $dms->getDB(); $revisionStatus = self::getRevisionStatus(); @@ -5351,7 +5634,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @param object $state */ function setWorkflowState($state) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if($this->_workflow) { $queryStr = "UPDATE `tblWorkflowDocumentContent` set `state`=". $state->getID() ." WHERE `id`=". $this->_workflow['id']; @@ -5371,7 +5654,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * or false in case of error, e.g. the version has not a workflow */ function getWorkflowState() { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$this->_workflow) $this->getWorkflow(); @@ -5381,14 +5664,12 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ if (!$this->_workflowState) { $queryStr= - "SELECT b.* FROM `tblWorkflowDocumentContent` a LEFT JOIN `tblWorkflowStates` b ON a.`state` = b.`id` WHERE `workflow`=". intval($this->_workflow->getID()) - ." AND a.`version`='".$this->_version - ."' AND a.`document` = '". $this->_document->getID() ."' "; + "SELECT b.* FROM `tblWorkflowDocumentContent` a LEFT JOIN `tblWorkflowStates` b ON a.`state` = b.id WHERE `a`.`id`=". $this->_workflow['id']; $recs = $db->getResultArray($queryStr); if (is_bool($recs) && !$recs) return false; $this->_workflowState = new SeedDMS_Core_Workflow_State($recs[0]['id'], $recs[0]['name'], $recs[0]['maxtime'], $recs[0]['precondfunc'], $recs[0]['documentstatus']); - $this->_workflowState->setDMS($this->_document->_dms); + $this->_workflowState->setDMS($this->_document->getDMS()); } return $this->_workflowState; } /* }}} */ @@ -5399,7 +5680,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @param object $workflow */ function setWorkflow($workflow, $user) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $this->getWorkflow(); if($this->_workflow) @@ -5443,11 +5724,11 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * or false in case of error, e.g. the version has not a workflow */ function getWorkflow() { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if (!isset($this->_workflow)) { $queryStr= - "SELECT b.* FROM `tblWorkflowDocumentContent` a LEFT JOIN `tblWorkflows` b ON a.`workflow` = b.`id` WHERE a.`version`='".$this->_version + "SELECT a.`id` as `wdcid`, a.`parent`, b.* FROM `tblWorkflowDocumentContent` a LEFT JOIN `tblWorkflows` b ON a.`workflow` = b.`id` WHERE a.`version`='".$this->_version ."' AND a.`document` = '". $this->_document->getID() ."' " ." AND a.`state` IS NOT NULL" ." ORDER BY `date` DESC LIMIT 1"; @@ -5456,8 +5737,8 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ return false; if(!$recs) return false; - $this->_workflow = array('id'=>(int)$recs[0]['wdcid'], 'parent'=>(int)$recs[0]['parent'], 'workflow'=>new SeedDMS_Core_Workflow($recs[0]['id'], $recs[0]['name'], $this->_document->_dms->getWorkflowState($recs[0]['initstate']), $recs[0]["layoutdata"])); - $this->_workflow['workflow']->setDMS($this->_document->_dms); + $this->_workflow = array('id'=>(int)$recs[0]['wdcid'], 'parent'=>(int)$recs[0]['parent'], 'workflow'=>new SeedDMS_Core_Workflow($recs[0]['id'], $recs[0]['name'], $this->_document->getDMS()->getWorkflowState($recs[0]['initstate']), $recs[0]["layoutdata"])); + $this->_workflow['workflow']->setDMS($this->_document->getDMS()); } return $this->_workflow['workflow']; } /* }}} */ @@ -5473,7 +5754,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return boolean true on success, otherwise false */ function rewriteWorkflowLog($workflowlog) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); /* Get the workflowdocumentcontent */ $queryStr = "SELECT `id` FROM `tblWorkflowDocumentContent` WHERE `tblWorkflowDocumentContent`.`document` = '". $this->_document->getID() ."' AND `tblWorkflowDocumentContent`.`version` = '". $this->_version ."'"; @@ -5518,7 +5799,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * or false in case of error */ function rewindWorkflow() { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $this->getWorkflow(); @@ -5561,7 +5842,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * or false in case of error */ function removeWorkflow($user, $unlink=false) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $this->getWorkflow(); @@ -5614,7 +5895,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @param object $subworkflow */ function getParentWorkflow() { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); /* document content must be in a workflow */ $this->getWorkflow(); @@ -5633,7 +5914,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ return false; if($recs[0]['workflow']) - return $this->_document->_dms->getWorkflow((int)$recs[0]['workflow']); + return $this->_document->getDMS()->getWorkflow((int)$recs[0]['workflow']); return false; } /* }}} */ @@ -5644,7 +5925,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @param object $subworkflow */ function runSubWorkflow($subworkflow) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); /* document content must be in a workflow */ $this->getWorkflow(); @@ -5678,7 +5959,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @param string comment for the transition trigger */ function returnFromSubWorkflow($user, $transition=null, $comment='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); /* document content must be in a workflow */ $this->getWorkflow(); @@ -5727,7 +6008,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return boolean true if user may trigger transaction */ function triggerWorkflowTransitionIsAllowed($user, $transition) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$this->_workflow) $this->getWorkflow(); @@ -5869,7 +6150,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * false in case of an error */ function triggerWorkflowTransition($user, $transition, $comment='') { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$this->_workflow) $this->getWorkflow(); @@ -5939,8 +6220,8 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * the next state will be reached if one of the transitions * leading to the given state can be processed. */ - if($nextstate->getPreCondFunc() == '') { - $workflow = $this->_workflow['workflow']; + if($nextstate->getPreCondFunc() == '') { + $workflow = $this->_workflow['workflow']; $transitions = $workflow->getPreviousTransitions($nextstate); foreach($transitions as $transition) { // echo "transition ".$transition->getID()." led to state ".$nextstate->getName()."
"; @@ -6014,7 +6295,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return array list of operations */ function getWorkflowLog($transition = null) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$this->_workflow) $this->getWorkflow(); @@ -6033,8 +6314,8 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ $workflowlogs = array(); for ($i = 0; $i < count($resArr); $i++) { - $workflow = $this->_document->_dms->getWorkflow($resArr[$i]["workflow"]); - $workflowlog = new SeedDMS_Core_Workflow_Log($resArr[$i]["id"], $this->_document->_dms->getDocument($resArr[$i]["document"]), $resArr[$i]["version"], $workflow, $this->_document->_dms->getUser($resArr[$i]["userid"]), $workflow->getTransition($resArr[$i]["transition"]), $resArr[$i]["date"], $resArr[$i]["comment"]); + $workflow = $this->_document->getDMS()->getWorkflow($resArr[$i]["workflow"]); + $workflowlog = new SeedDMS_Core_Workflow_Log($resArr[$i]["id"], $this->_document->getDMS()->getDocument($resArr[$i]["document"]), $resArr[$i]["version"], $workflow, $this->_document->getDMS()->getUser($resArr[$i]["userid"]), $workflow->getTransition($resArr[$i]["transition"]), $resArr[$i]["date"], $resArr[$i]["comment"]); $workflowlog->setDMS($this); if($this->_workflow && $transition) $workflowlogs[] = $workflowlog; @@ -6052,7 +6333,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ * @return array list of operations */ function getLastWorkflowTransition() { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$this->_workflow) $this->getWorkflow(); @@ -6069,7 +6350,7 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ $workflowlogs = array(); $i = 0; - $workflowlog = new SeedDMS_Core_Workflow_Log($resArr[$i]["id"], $this->_document->_dms->getDocument($resArr[$i]["document"]), $resArr[$i]["version"], $this->_workflow, $this->_document->_dms->getUser($resArr[$i]["userid"]), $this->_workflow->getTransition($resArr[$i]["transition"]), $resArr[$i]["date"], $resArr[$i]["comment"]); + $workflowlog = new SeedDMS_Core_Workflow_Log($resArr[$i]["id"], $this->_document->getDMS()->getDocument($resArr[$i]["document"]), $resArr[$i]["version"], $this->_workflow, $this->_document->getDMS()->getUser($resArr[$i]["userid"]), $this->_workflow->getTransition($resArr[$i]["transition"]), $resArr[$i]["date"], $resArr[$i]["comment"]); $workflowlog->setDMS($this); return $workflowlog; @@ -6102,6 +6383,49 @@ class SeedDMS_Core_DocumentContent extends SeedDMS_Core_Object { /* {{{ */ return $needwkflaction; } /* }}} */ + /** + * Checks the internal data of the document version and repairs it. + * Currently, this function only repairs a missing filetype + * + * @return boolean true on success, otherwise false + */ + function repair() { /* {{{ */ + $dms = $this->_document->getDMS(); + $db = $this->_dms->getDB(); + + if(file_exists($this->_dms->contentDir.$this->_document->getDir() . $this->_version . $this->_fileType)) { + if(strlen($this->_fileType) < 2) { + switch($this->_mimeType) { + case "application/pdf": + case "image/png": + case "image/gif": + case "image/jpg": + $expect = substr($this->_mimeType, -3, 3); + if($this->_fileType != '.'.$expect) { + $db->startTransaction(); + $queryStr = "UPDATE `tblDocumentContent` SET `fileType`='.".$expect."' WHERE `id` = ". $this->_id; + $res = $db->getResult($queryStr); + if ($res) { + if(!SeedDMS_Core_File::renameFile($this->_dms->contentDir.$this->_document->getDir() . $this->_version . $this->_fileType, $this->_dms->contentDir.$this->_document->getDir() . $this->_version . '.' . $expect)) { + $db->rollbackTransaction(); + } else { + $db->commitTransaction(); + } + } else { + $db->rollbackTransaction(); + } + } + break; + } + } + } elseif(file_exists($this->_document->getDir() . $this->_version . '.')) { + echo "no file"; + } else { + echo $this->_dms->contentDir.$this->_document->getDir() . $this->_version . $this->_fileType; + } + return true; + } /* }}} */ + } /* }}} */ @@ -6188,8 +6512,9 @@ class SeedDMS_Core_DocumentLink { /* {{{ */ * @return bool|SeedDMS_Core_User */ function getUser() { - if (!isset($this->_user)) - $this->_user = $this->_document->_dms->getUser($this->_userID); + if (!isset($this->_user)) { + $this->_user = $this->_document->getDMS()->getUser($this->_userID); + } return $this->_user; } @@ -6212,11 +6537,11 @@ class SeedDMS_Core_DocumentLink { /* {{{ */ * @return int either M_NONE or M_READ */ function getAccessMode($u, $source, $target) { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); /* Check if 'onCheckAccessDocumentLink' callback is set */ - if(isset($this->_dms->callbacks['onCheckAccessDocumentLink'])) { - foreach($this->_dms->callbacks['onCheckAccessDocumentLink'] as $callback) { + if(isset($dms->callbacks['onCheckAccessDocumentLink'])) { + foreach($dms->callbacks['onCheckAccessDocumentLink'] as $callback) { if(($ret = call_user_func($callback[0], $callback[1], $this, $u, $source, $target)) > 0) { return $ret; } @@ -6365,7 +6690,7 @@ class SeedDMS_Core_DocumentFile { /* {{{ */ * @param string $newComment string new comment of document */ function setComment($newComment) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr = "UPDATE `tblDocumentFiles` SET `comment` = ".$db->qstr($newComment)." WHERE `document` = ".$this->_document->getId()." AND `id` = ". $this->_id; if (!$db->getResult($queryStr)) @@ -6388,7 +6713,7 @@ class SeedDMS_Core_DocumentFile { /* {{{ */ * @return boolean true on success */ function setDate($date) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!$date) $date = time(); @@ -6435,7 +6760,7 @@ class SeedDMS_Core_DocumentFile { /* {{{ */ * @param $newComment string new name of document */ function setName($newName) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr = "UPDATE `tblDocumentFiles` SET `name` = ".$db->qstr($newName)." WHERE `document` = ".$this->_document->getId()." AND `id` = ". $this->_id; if (!$db->getResult($queryStr)) @@ -6450,7 +6775,7 @@ class SeedDMS_Core_DocumentFile { /* {{{ */ */ function getUser() { if (!isset($this->_user)) - $this->_user = $this->_document->_dms->getUser($this->_userID); + $this->_user = $this->_document->getDMS()->getUser($this->_userID); return $this->_user; } @@ -6472,7 +6797,7 @@ class SeedDMS_Core_DocumentFile { /* {{{ */ * @param $newComment string new version of document */ function setVersion($newVersion) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); if(!is_numeric($newVersion) && $newVersion != '') return false; @@ -6496,7 +6821,7 @@ class SeedDMS_Core_DocumentFile { /* {{{ */ * @param $newComment string new comment of document */ function setPublic($newPublic) { /* {{{ */ - $db = $this->_document->_dms->getDB(); + $db = $this->_document->getDMS()->getDB(); $queryStr = "UPDATE `tblDocumentFiles` SET `public` = ".($newPublic ? 1 : 0)." WHERE `document` = ".$this->_document->getId()." AND `id` = ". $this->_id; if (!$db->getResult($queryStr)) @@ -6518,7 +6843,7 @@ class SeedDMS_Core_DocumentFile { /* {{{ */ * @return integer either M_NONE or M_READ */ function getAccessMode($u) { /* {{{ */ - $dms = $this->_document->_dms; + $dms = $this->_document->getDMS(); /* Check if 'onCheckAccessDocumentLink' callback is set */ if(isset($this->_dms->callbacks['onCheckAccessDocumentFile'])) { diff --git a/SeedDMS_Core/Core/inc.ClassFolder.php b/SeedDMS_Core/Core/inc.ClassFolder.php index 748b4e2a8..55ba6eaa8 100644 --- a/SeedDMS_Core/Core/inc.ClassFolder.php +++ b/SeedDMS_Core/Core/inc.ClassFolder.php @@ -129,6 +129,15 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { $this->_notifyList = array(); } /* }}} */ + /** + * Check if this object is of type 'folder'. + * + * @param string $type type of object + */ + public function isType($type) { /* {{{ */ + return $type == 'folder'; + } /* }}} */ + /** * Return an array of database fields which used for searching * a term entered in the database search form @@ -168,6 +177,22 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { return $sql; } /* }}} */ + /** + * Return a folder by its database record + * + * @param array $resArr array of folder data as returned by database + * @param SeedDMS_Core_DMS $dms + * @return SeedDMS_Core_Folder|bool instance of SeedDMS_Core_Folder if document exists + */ + public static function getInstanceByData($resArr, $dms) { /* {{{ */ + $classname = $dms->getClassname('folder'); + /** @var SeedDMS_Core_Folder $folder */ + $folder = new $classname($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]); + $folder->setDMS($dms); + $folder = $folder->applyDecorators(); + return $folder; + } /* }}} */ + /** * Return a folder by its id * @@ -186,14 +211,34 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { else if (count($resArr) != 1) return null; + return self::getInstanceByData($resArr[0], $dms); + $resArr = $resArr[0]; $classname = $dms->getClassname('folder'); /** @var SeedDMS_Core_Folder $folder */ $folder = new $classname($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]); $folder->setDMS($dms); + $folder = $folder->applyDecorators(); return $folder; } /* }}} */ + /** + * Apply decorators + * + * @return object final object after all decorators has been applied + */ + function applyDecorators() { /* {{{ */ + if($decorators = $this->_dms->getDecorators('folder')) { + $s = $this; + foreach($decorators as $decorator) { + $s = new $decorator($s); + } + return $s; + } else { + return $this; + } + } /* }}} */ + /** * Get the name of the folder. * @@ -448,7 +493,7 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { $this->_defaultAccess = $mode; if(!$noclean) - self::cleanNotifyList(); + $this->cleanNotifyList(); return true; } /* }}} */ @@ -481,7 +526,7 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { $this->_inheritAccess = $inheritAccess; if(!$noclean) - self::cleanNotifyList(); + $this->cleanNotifyList(); return true; } /* }}} */ @@ -520,6 +565,26 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { return $resArr[0]['c']; } /* }}} */ + /** + * Check if folder has as subfolder with given name + * + * @param string $name + * @return bool true if subfolder exists, false if not or in case + * of an error + */ + function hasSubFolderByName($name) { /* {{{ */ + $db = $this->_dms->getDB(); + /* Always check the database instead of iterating over $this->_documents, because + * it is probably not slower + */ + $queryStr = "SELECT count(*) as c FROM `tblFolders` WHERE `parent` = " . $this->_id . " AND `name` = ".$db->qstr($name); + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + return ($resArr[0]['c'] > 0); + } /* }}} */ + /** * Returns a list of subfolders * This function does not check for access rights. Use @@ -539,9 +604,9 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { if (!isset($this->_subFolders)) { $queryStr = "SELECT * FROM `tblFolders` WHERE `parent` = " . $this->_id; - if ($orderby=="n") $queryStr .= " ORDER BY `name`"; - elseif ($orderby=="s") $queryStr .= " ORDER BY `sequence`"; - elseif ($orderby=="d") $queryStr .= " ORDER BY `date`"; + if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`"; + elseif ($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`"; + elseif ($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`"; if($dir == 'desc') $queryStr .= " DESC"; if(is_int($limit) && $limit > 0) { @@ -554,9 +619,11 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { if (is_bool($resArr) && $resArr == false) return false; + $classname = $this->_dms->getClassname('folder'); $this->_subFolders = array(); for ($i = 0; $i < count($resArr); $i++) - $this->_subFolders[$i] = $this->_dms->getFolder($resArr[$i]["id"]); +// $this->_subFolders[$i] = $this->_dms->getFolder($resArr[$i]["id"]); + $this->_subFolders[$i] = $classname::getInstanceByData($resArr[$i], $this->_dms); } return $this->_subFolders; @@ -672,15 +739,11 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { * @return boolean true if folder is a subfolder */ function isDescendant($folder) { /* {{{ */ - if ($this->_parentID == $folder->getID()) - return true; - elseif (isset($this->_parentID)) { - $res = $this->getParent(); - if (!$res) return false; - - return $this->_parent->isDescendant($folder); - } else + if(!$this->getParent()) return false; + if($this->getParent()->getID() == $folder->getID()) + return true; + return $this->getParent()->isDescendant($folder); } /* }}} */ /** @@ -713,10 +776,9 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { */ function hasDocumentByName($name) { /* {{{ */ $db = $this->_dms->getDB(); - if (isset($this->_documents)) { - /** @noinspection PhpUndefinedFieldInspection */ /** @todo not $this->_documents? */ - return count($this->documents); - } + /* Always check the database instead of iterating over $this->_documents, because + * it is probably not slower + */ $queryStr = "SELECT count(*) as c FROM `tblDocuments` WHERE `folder` = " . $this->_id . " AND `name` = ".$db->qstr($name); $resArr = $db->getResultArray($queryStr); if (is_bool($resArr) && !$resArr) @@ -742,10 +804,10 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { $db = $this->_dms->getDB(); if (!isset($this->_documents)) { - $queryStr = "SELECT * FROM `tblDocuments` WHERE `folder` = " . $this->_id; - if ($orderby=="n") $queryStr .= " ORDER BY `name`"; - elseif($orderby=="s") $queryStr .= " ORDER BY `sequence`"; - elseif($orderby=="d") $queryStr .= " ORDER BY `date`"; + $queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lock` FROM `tblDocuments` LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id` = `tblDocumentLocks`.`document` WHERE `folder` = " . $this->_id; + if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`"; + elseif($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`"; + elseif($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`"; if($dir == 'desc') $queryStr .= " DESC"; if(is_int($limit) && $limit > 0) { @@ -759,9 +821,11 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { return false; $this->_documents = array(); + $classname = $this->_dms->getClassname('document'); foreach ($resArr as $row) { -// array_push($this->_documents, new SeedDMS_Core_Document($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], isset($row["lockUser"])?$row["lockUser"]:NULL, $row["keywords"], $row["sequence"])); - array_push($this->_documents, $this->_dms->getDocument($row["id"])); + $row['lock'] = !$row['lock'] ? -1 : $row['lock']; +// array_push($this->_documents, $this->_dms->getDocument($row["id"])); + array_push($this->_documents, $classname::getInstanceByData($row, $this->_dms)); } } return $this->_documents; @@ -1024,6 +1088,12 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { * Remove recursively a folder * * Removes a folder, all its subfolders and documents + * This method triggers the callbacks onPreRemoveFolder and onPostRemoveFolder. + * If onPreRemoveFolder returns a boolean then this method will return + * imediately with the value returned by the callback. Otherwise the + * regular removal is executed, which in turn + * triggers further onPreRemoveFolder and onPostRemoveFolder callbacks + * and its counterparts for documents (onPreRemoveDocument, onPostRemoveDocument). * * @return boolean true on success, false in case of an error */ @@ -1079,6 +1149,62 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { return $ret; } /* }}} */ + /** + * Empty recursively a folder + * + * Removes all subfolders and documents of a folder but not the folder itself + * This method will call remove() on all its children. + * This method triggers the callbacks onPreEmptyFolder and onPostEmptyFolder. + * If onPreEmptyFolder returns a boolean then this method will return + * imediately. + * Be aware that the recursive calls of remove() will trigger the callbacks + * onPreRemoveFolder, onPostRemoveFolder, onPreRemoveDocument and onPostRemoveDocument. + * + * @return boolean true on success, false in case of an error + */ + function emptyFolder() { /* {{{ */ + /** @noinspection PhpUnusedLocalVariableInspection */ + $db = $this->_dms->getDB(); + + /* Check if 'onPreEmptyFolder' callback is set */ + if(isset($this->_dms->callbacks['onPreEmptyFolder'])) { + foreach($this->_dms->callbacks['onPreEmptyFolder'] as $callback) { + $ret = call_user_func($callback[0], $callback[1], $this); + if(is_bool($ret)) + return $ret; + } + } + + //Entfernen der Unterordner und Dateien + $res = $this->getSubFolders(); + if (is_bool($res) && !$res) return false; + $res = $this->getDocuments(); + if (is_bool($res) && !$res) return false; + + foreach ($this->_subFolders as $subFolder) { + $res = $subFolder->remove(); + if (!$res) { + return false; + } + } + + foreach ($this->_documents as $document) { + $res = $document->remove(); + if (!$res) { + return false; + } + } + + /* Check if 'onPostEmptyFolder' callback is set */ + if(isset($this->_dms->callbacks['onPostEmptyFolder'])) { + foreach($this->_dms->callbacks['onPostEmptyFolder'] as $callback) { + call_user_func($callback[0], $callback[1], $this); + } + } + + return true; + } /* }}} */ + /** * Returns a list of access privileges * @@ -1152,7 +1278,7 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { unset($this->_accessList); if(!$noclean) - self::cleanNotifyList(); + $this->cleanNotifyList(); return true; } /* }}} */ diff --git a/SeedDMS_Core/Core/inc.ClassIterator.php b/SeedDMS_Core/Core/inc.ClassIterator.php new file mode 100644 index 000000000..3dd89148e --- /dev/null +++ b/SeedDMS_Core/Core/inc.ClassIterator.php @@ -0,0 +1,229 @@ + + * @copyright Copyright (C) 2010, Uwe Steinmann + * @version Release: @package_version@ + */ + +class DocumentIterator implements Iterator { + /** + * @var object folder + */ + protected $_folder; + + /** + * @var object dms + */ + protected $_dms; + + /** + * @var array documents + */ + protected $_documents; + + public function __construct($folder) { + $this->_folder = $folder; + $this->_dms = $folder->getDMS(); + $this->_documents = array(); + $this->_pointer = 0; + $this->_cache = array(); + $this->populate(); + } + + public function rewind() { + $this->_pointer = 0; + } + + public function valid() { + return isset($this->_documents[$this->_pointer]); + } + + public function next() { + $this->_pointer++; + } + + public function key() { + return $this->_folders[$this->_pointer]; + } + + public function current() { + if($this->_documents[$this->_pointer]) { + $documentid = $this->_documents[$this->_pointer]['id']; + if(!isset($this->_cache[$documentid])) { +// echo $documentid." not cached
"; + $this->_cache[$documentid] = $this->_dms->getdocument($documentid); + } + return $this->_cache[$documentid]; + } + return null; + } + + private function populate($orderby="", $dir="asc", $limit=0, $offset=0) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "SELECT `id` FROM `tblDocuments` WHERE `folder` = " . $this->_folder->getID(); + + if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`"; + elseif ($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`"; + elseif ($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`"; + if($dir == 'desc') + $queryStr .= " DESC"; + if(is_int($limit) && $limit > 0) { + $queryStr .= " LIMIT ".$limit; + if(is_int($offset) && $offset > 0) + $queryStr .= " OFFSET ".$offset; + } + + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + $this->_documents = $resArr; + } /* }}} */ +} + +class FolderIterator implements Iterator { /* {{{ */ + /** + * @var object folder + */ + protected $_folder; + + /** + * @var object dms + */ + protected $_dms; + + /** + * @var array documents + */ + protected $_folders; + + public function __construct($folder) { /* {{{ */ + $this->_folder = $folder; + $this->_dms = $folder->getDMS(); + $this->_folders = array(); + $this->_pointer = 0; + $this->_cache = array(); + $this->populate(); + } /* }}} */ + + public function rewind() { /* {{{ */ + $this->_pointer = 0; + } /* }}} */ + + public function valid() { /* {{{ */ + return isset($this->_folders[$this->_pointer]); + } /* }}} */ + + public function next() { /* {{{ */ + $this->_pointer++; + } /* }}} */ + + public function key() { /* {{{ */ + return $this->_folders[$this->_pointer]; + } /* }}} */ + + public function current() { /* {{{ */ + if($this->_folders[$this->_pointer]) { + $folderid = $this->_folders[$this->_pointer]['id']; + if(!isset($this->_cache[$folderid])) { +// echo $folderid." not cached
"; + $this->_cache[$folderid] = $this->_dms->getFolder($folderid); + } + return $this->_cache[$folderid]; + } + return null; + } /* }}} */ + + private function populate($orderby="", $dir="asc", $limit=0, $offset=0) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "SELECT `id` FROM `tblFolders` WHERE `parent` = " . $this->_folder->getID(); + + if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`"; + elseif ($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`"; + elseif ($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`"; + if($dir == 'desc') + $queryStr .= " DESC"; + if(is_int($limit) && $limit > 0) { + $queryStr .= " LIMIT ".$limit; + if(is_int($offset) && $offset > 0) + $queryStr .= " OFFSET ".$offset; + } + + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + $this->_folders = $resArr; + } /* }}} */ +} /* }}} */ + +/** + * The FolderFilterIterator checks if the given user has access on + * the current folder. + * FilterIterator uses an inner iterator passed to the constructor + * to iterate over the sub folders of a folder. + * + $iter = new FolderIterator($folder); + $iter2 = new FolderFilterIterator($iter, $user); + foreach($iter2 as $ff) { + echo $ff->getName()."
"; + } + */ +class FolderFilterIterator extends FilterIterator { /* {{{ */ + public function __construct(Iterator $iterator , $filter ) { + parent::__construct($iterator); + $this->userFilter = $filter; + } + public function accept() { /* {{{ */ + $folder = $this->getInnerIterator()->current(); + echo "accept() for ".$folder->getName()."
"; + return true; + } /* }}} */ +} /* }}} */ + +/** + $iter = new RecursiveFolderIterator($folder); + $iter2 = new RecursiveIteratorIterator($iter, RecursiveIteratorIterator::SELF_FIRST); + foreach($iter2 as $ff) { + echo $ff->getID().': '.$ff->getName()."
"; + } + */ +class RecursiveFolderIterator extends FolderIterator implements RecursiveIterator { /* {{{ */ + + public function hasChildren() { /* {{{ */ + $db = $this->_dms->getDB(); + $queryStr = "SELECT id FROM `tblFolders` WHERE `parent` = ".(int) $this->current()->getID(); + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + return true; + } /* }}} */ + + public function getChildren() { /* {{{ */ + return new RecursiveFolderIterator($this->current()); + } /* }}} */ +} /* }}} */ + +class RecursiveFolderFilterIterator extends FolderFilterIterator { /* {{{ */ + public function hasChildren() { /* {{{ */ + $db = $this->_dms->getDB(); + $queryStr = "SELECT id FROM `tblFolders` WHERE `parent` = ".(int) $this->current()->getID(); + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + return true; + } /* }}} */ + + public function getChildren() { /* {{{ */ + return new RecursiveFolderIterator($this->current()); + } /* }}} */ + +} /* }}} */ diff --git a/SeedDMS_Core/Core/inc.ClassObject.php b/SeedDMS_Core/Core/inc.ClassObject.php index e53d2416c..101f3bf2c 100644 --- a/SeedDMS_Core/Core/inc.ClassObject.php +++ b/SeedDMS_Core/Core/inc.ClassObject.php @@ -47,6 +47,15 @@ class SeedDMS_Core_Object { /* {{{ */ $this->_dms = null; } /* }}} */ + /** + * Check if this object is of a given type. + * + * This method must be implemened in the child class + * + * @param string $type type of object + */ + public function isType($type) {return false;} + /** * Set dms this object belongs to. * @@ -57,23 +66,27 @@ class SeedDMS_Core_Object { /* {{{ */ * * @param SeedDMS_Core_DMS $dms reference to dms */ - function setDMS($dms) { /* {{{ */ + public function setDMS($dms) { /* {{{ */ $this->_dms = $dms; } /* }}} */ + public function getDMS() { /* {{{ */ + return $this->_dms; + } /* }}} */ + /** * Return the internal id of the document * * @return integer id of document */ - function getID() { return $this->_id; } + public function getID() { return $this->_id; } /** * Returns all attributes set for the object * * @return array|bool */ - function getAttributes() { /* {{{ */ + public function getAttributes() { /* {{{ */ if (!$this->_attributes) { $db = $this->_dms->getDB(); @@ -113,7 +126,7 @@ class SeedDMS_Core_Object { /* {{{ */ * @return array|string value of attritbute or false. The value is an array * if the attribute is defined as multi value */ - function getAttribute($attrdef) { /* {{{ */ + public function getAttribute($attrdef) { /* {{{ */ if (!$this->_attributes) { $this->getAttributes(); } @@ -133,7 +146,7 @@ class SeedDMS_Core_Object { /* {{{ */ * @return array|string value of attritbute or false. The value is an array * if the attribute is defined as multi value */ - function getAttributeValue($attrdef) { /* {{{ */ + public function getAttributeValue($attrdef) { /* {{{ */ if (!$this->_attributes) { $this->getAttributes(); } @@ -171,7 +184,7 @@ class SeedDMS_Core_Object { /* {{{ */ * @return array|bool * even if the attribute is not defined as multi value */ - function getAttributeValueAsArray($attrdef) { /* {{{ */ + public function getAttributeValueAsArray($attrdef) { /* {{{ */ if (!$this->_attributes) { $this->getAttributes(); } @@ -194,7 +207,7 @@ class SeedDMS_Core_Object { /* {{{ */ * @return string value of attritbute or false. The value is always a string * even if the attribute is defined as multi value */ - function getAttributeValueAsString($attrdef) { /* {{{ */ + public function getAttributeValueAsString($attrdef) { /* {{{ */ if (!$this->_attributes) { $this->getAttributes(); } @@ -214,7 +227,7 @@ class SeedDMS_Core_Object { /* {{{ */ * must be an array * @return boolean true if operation was successful, otherwise false */ - function setAttributeValue($attrdef, $value) { /* {{{ */ + public function setAttributeValue($attrdef, $value) { /* {{{ */ $db = $this->_dms->getDB(); if (!$this->_attributes) { $this->getAttributes(); @@ -265,7 +278,7 @@ class SeedDMS_Core_Object { /* {{{ */ * @param SeedDMS_Core_AttributeDefinition $attrdef * @return boolean true if operation was successful, otherwise false */ - function removeAttribute($attrdef) { /* {{{ */ + public function removeAttribute($attrdef) { /* {{{ */ $db = $this->_dms->getDB(); if (!$this->_attributes) { $this->getAttributes(); diff --git a/SeedDMS_Core/Core/inc.ClassTransmittal.php b/SeedDMS_Core/Core/inc.ClassTransmittal.php index cd63cfbe0..719f25131 100644 --- a/SeedDMS_Core/Core/inc.ClassTransmittal.php +++ b/SeedDMS_Core/Core/inc.ClassTransmittal.php @@ -79,7 +79,7 @@ class SeedDMS_Core_Transmittal { */ var $_dms; - function SeedDMS_Core_Transmittal($id, $user, $name, $comment, $isPublic=0, $date='') { + function __construct($id, $user, $name, $comment, $isPublic=0, $date='') { $this->_id = $id; $this->_name = $name; $this->_comment = $comment; @@ -312,7 +312,7 @@ class SeedDMS_Core_TransmittalItem { */ var $_date; - function SeedDMS_Core_TransmittalItem($id, $transmittal, $content, $date='') { + function __construct($id, $transmittal, $content, $date='') { $this->_id = $id; $this->_transmittal = $transmittal; $this->_content = $content; diff --git a/SeedDMS_Core/Core/inc.ClassUser.php b/SeedDMS_Core/Core/inc.ClassUser.php index f6db633c2..201bfcfa9 100644 --- a/SeedDMS_Core/Core/inc.ClassUser.php +++ b/SeedDMS_Core/Core/inc.ClassUser.php @@ -62,7 +62,7 @@ class SeedDMS_Core_Role { /* {{{ */ const role_admin = '1'; const role_guest = '2'; - function SeedDMS_Core_Role($id, $name, $role, $noaccess=array()) { /* {{{ */ + function __construct($id, $name, $role, $noaccess=array()) { /* {{{ */ $this->_id = $id; $this->_name = $name; $this->_role = $role; @@ -182,7 +182,7 @@ class SeedDMS_Core_Role { /* {{{ */ * * @return boolean true on success or false in case of an error */ - function remove($user) { /* {{{ */ + function remove() { /* {{{ */ $db = $this->_dms->getDB(); $queryStr = "DELETE FROM `tblRoles` WHERE `id` = " . $this->_id; @@ -713,7 +713,6 @@ class SeedDMS_Core_User { /* {{{ */ */ function setRole($newrole) { /* {{{ */ $db = $this->_dms->getDB(); - $newrole = intval($newrole); if(is_object($newrole)) $queryStr = "UPDATE `tblUsers` SET `role` = " . $newrole->getID() . " WHERE `id` = " . $this->_id; @@ -898,70 +897,147 @@ class SeedDMS_Core_User { /* {{{ */ /** * Remove user from all processes * - * This method adds another log entry to the reviews and approvals + * This method adds another log entry to the reviews, approvals, receptions, revisions, * which indicates the user has been deleted from the process. By default it will - * do so for each review/approval regardless of its current state. So even - * reviews/approvals already processed by the user will be added the log + * do so for each review/approval/reception/revision regardless of its current state unless + * the user has been removed already (status=-2). So even + * reviews/approvals/receptions/revisions already processed by the user will be added the log * entry. Only if the last log entry was a removal already, it will not be * added a second time. + * This behaviour can be changed by passing a list of states in the optional + * argument $states. Only reviews, etc. in the given state will be affected. + * This allows to remove the user only if the review, etc. has not been done + * (state = 0). + * + * The last optional parameter $newuser is for replacing the user currently in + * charge by another user. * * @param object $user the user doing the removal (needed for entry in * review and approve log). * @param array $states remove user only from reviews/approvals in one of the states - * If passing array(0), the method will operate on reviews/approval which - * has not been touched. + * e.g. if passing array('review'=>array(0)), the method will operate on + * reviews which has not been touched yet. + * @param object user who is take over the processes * @return boolean true on success or false in case of an error */ - private function __removeFromProcesses($user, $states = array()) { /* {{{ */ + private function __removeFromProcesses($user, $states = array(), $newuser=null) { /* {{{ */ $db = $this->_dms->getDB(); + /* Get a list of all reviews, even those of older document versions */ $reviewStatus = $this->getReviewStatus(); + $db->startTransaction(); foreach ($reviewStatus["indstatus"] as $ri) { if($ri['status'] != -2 && (!isset($states['review']) || in_array($ri['status'], $states['review']))) { $queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ". "VALUES ('". $ri["reviewID"] ."', '-2', 'Reviewer removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')"; $res=$db->getResult($queryStr); if(!$res) { + $db->rollbackTransaction(); return false; } + /* Only reviews not done already can be transferred to a new user */ + if($newuser && $ri['status'] == 0) { + if($doc = $this->_dms->getDocument($ri['documentID'])) { + if($version = $doc->getContentByVersion($ri['version'])) { + $ret = $version->addIndReviewer($newuser, $user); + /* returns -3 if the user is already a reviewer */ + if($ret != 0 && $ret != -3) { + $db->rollbackTransaction(); + return false; + } + } + } + } } } + $db->commitTransaction(); + /* Get a list of all approvals, even those of older document versions */ $approvalStatus = $this->getApprovalStatus(); + $db->startTransaction(); foreach ($approvalStatus["indstatus"] as $ai) { if($ai['status'] != -2 && (!isset($states['approval']) || in_array($ai['status'], $states['approval']))) { $queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ". "VALUES ('". $ai["approveID"] ."', '-2', 'Approver removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')"; $res=$db->getResult($queryStr); if(!$res) { + $db->rollbackTransaction(); return false; } + /* Only approvals not done already can be transferred to a new user */ + if($newuser && $ai['status'] == 0) { + if($doc = $this->_dms->getDocument($ai['documentID'])) { + if($version = $doc->getContentByVersion($ai['version'])) { + $ret = $version->addIndReviewer($newuser, $user); + /* returns -3 if the user is already a reviewer */ + if($ret != 0 && $ret != -3) { + $db->rollbackTransaction(); + return false; + } + } + } + } } } + $db->commitTransaction(); + /* Get a list of all receptions, even those of older document versions */ $receiptStatus = $this->getReceiptStatus(); + $db->startTransaction(); foreach ($receiptStatus["indstatus"] as $ri) { if($ri['status'] != -2 && (!isset($states['receipt']) || in_array($ri['status'], $states['receipt']))) { $queryStr = "INSERT INTO `tblDocumentReceiptLog` (`receiptID`, `status`, `comment`, `date`, `userID`) ". "VALUES ('". $ri["receiptID"] ."', '-2', 'Recipient removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')"; $res=$db->getResult($queryStr); if(!$res) { + $db->rollbackTransaction(); return false; } + /* Only receptions not done already can be transferred to a new user */ + if($newuser && $ri['status'] == 0) { + if($doc = $this->_dms->getDocument($ri['documentID'])) { + if($version = $doc->getContentByVersion($ri['version'])) { + $ret = $version->addIndRecipient($newuser, $user); + /* returns -3 if the user is already a recipient */ + if($ret != 0 && $ret != -3) { + $db->rollbackTransaction(); + return false; + } + } + } + } } } + $db->commitTransaction(); + /* Get a list of all revisions, even those of older document versions */ $revisionStatus = $this->getRevisionStatus(); + $db->startTransaction(); foreach ($revisionStatus["indstatus"] as $ri) { if($ri['status'] != -2 && (!isset($states['revision']) || in_array($ri['status'], $states['revision']))) { $queryStr = "INSERT INTO `tblDocumentRevisionLog` (`revisionID`, `status`, `comment`, `date`, `userID`) ". "VALUES ('". $ri["revisionID"] ."', '-2', 'Revisor removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')"; $res=$db->getResult($queryStr); if(!$res) { + $db->rollbackTransaction(); return false; } + /* Only revisions not done already can be transferred to a new user */ + if($newuser && $ri['status'] == 0) { + if($doc = $this->_dms->getDocument($ri['documentID'])) { + if($version = $doc->getContentByVersion($ri['version'])) { + $ret = $version->addIndRevisor($newuser, $user); + /* returns -3 if the user is already a revisor */ + if($ret != 0 && $ret != -3) { + $db->rollbackTransaction(); + return false; + } + } + } + } } } + $db->commitTransaction(); return true; } /* }}} */ @@ -976,11 +1052,11 @@ class SeedDMS_Core_User { /* {{{ */ * @param array $states remove user only from reviews/approvals in one of the states * @return boolean true on success or false in case of an error */ - public function removeFromProcesses($user, $states=array()) { /* {{{ */ + public function removeFromProcesses($user, $states=array(), $newuser=null) { /* {{{ */ $db = $this->_dms->getDB(); $db->startTransaction(); - if(!$this->__removeFromProcesses($user, $states)) { + if(!$this->__removeFromProcesses($user, $states, $newuser)) { $db->rollbackTransaction(); return false; } diff --git a/SeedDMS_Core/Core/inc.FileUtils.php b/SeedDMS_Core/Core/inc.FileUtils.php index abc56fb86..dc6238063 100644 --- a/SeedDMS_Core/Core/inc.FileUtils.php +++ b/SeedDMS_Core/Core/inc.FileUtils.php @@ -25,50 +25,50 @@ * @version Release: @package_version@ */ class SeedDMS_Core_File { - /** - * @param $old - * @param $new - * @return bool - */ - static function renameFile($old, $new) { /* {{{ */ + /** + * @param $old + * @param $new + * @return bool + */ + static function renameFile($old, $new) { /* {{{ */ return @rename($old, $new); } /* }}} */ - /** - * @param $file - * @return bool - */ - static function removeFile($file) { /* {{{ */ + /** + * @param $file + * @return bool + */ + static function removeFile($file) { /* {{{ */ return @unlink($file); } /* }}} */ - /** - * @param $source - * @param $target - * @return bool - */ - static function copyFile($source, $target) { /* {{{ */ + /** + * @param $source + * @param $target + * @return bool + */ + static function copyFile($source, $target) { /* {{{ */ return @copy($source, $target); } /* }}} */ - /** - * @param $source - * @param $target - * @return bool - */ - static function moveFile($source, $target) { /* {{{ */ - /** @noinspection PhpUndefinedFunctionInspection */ - if (!@copyFile($source, $target)) + /** + * @param $source + * @param $target + * @return bool + */ + static function moveFile($source, $target) { /* {{{ */ + /** @noinspection PhpUndefinedFunctionInspection */ + if (!@copyFile($source, $target)) return false; - /** @noinspection PhpUndefinedFunctionInspection */ - return @removeFile($source); + /** @noinspection PhpUndefinedFunctionInspection */ + return @removeFile($source); } /* }}} */ - /** - * @param $file - * @return bool|int - */ - static function fileSize($file) { /* {{{ */ + /** + * @param $file + * @return bool|int + */ + static function fileSize($file) { /* {{{ */ if(!$a = fopen($file, 'r')) return false; fseek($a, 0, SEEK_END); @@ -77,22 +77,22 @@ class SeedDMS_Core_File { return $filesize; } /* }}} */ - /** - * @param $size - * @param array $sizes - * @return string - */ - static function format_filesize($size, $sizes = array('Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')) { /* {{{ */ + /** + * @param $size + * @param array $sizes + * @return string + */ + static function format_filesize($size, $sizes = array('Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')) { /* {{{ */ if ($size == 0) return('0 Bytes'); - /** @noinspection PhpIllegalArrayKeyTypeInspection */ - return (round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $sizes[$i]); + /** @noinspection PhpIllegalArrayKeyTypeInspection */ + return (round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $sizes[$i]); } /* }}} */ - /** - * @param $str - * @return bool|int - */ - static function parse_filesize($str) { /* {{{ */ + /** + * @param $str + * @return bool|int + */ + static function parse_filesize($str) { /* {{{ */ preg_replace('/\s\s+/', ' ', $str); if(strtoupper(substr($str, -1)) == 'B') { $value = (int) substr($str, 0, -2); @@ -115,32 +115,32 @@ class SeedDMS_Core_File { return $value; break; } - /** @noinspection PhpUnreachableStatementInspection */ - return false; + /** @noinspection PhpUnreachableStatementInspection */ + return false; } /* }}} */ - /** - * @param $file - * @return string - */ - static function checksum($file) { /* {{{ */ + /** + * @param $file + * @return string + */ + static function checksum($file) { /* {{{ */ return md5_file($file); } /* }}} */ - /** - * @param $old - * @param $new - * @return bool - */ - static function renameDir($old, $new) { /* {{{ */ + /** + * @param $old + * @param $new + * @return bool + */ + static function renameDir($old, $new) { /* {{{ */ return @rename($old, $new); } /* }}} */ - /** - * @param $path - * @return bool - */ - static function makeDir($path) { /* {{{ */ + /** + * @param $path + * @return bool + */ + static function makeDir($path) { /* {{{ */ if( !is_dir( $path ) ){ $res=@mkdir( $path , 0777, true); @@ -195,11 +195,11 @@ class SeedDMS_Core_File { */ } /* }}} */ - /** - * @param $path - * @return bool - */ - static function removeDir($path) { /* {{{ */ + /** + * @param $path + * @return bool + */ + static function removeDir($path) { /* {{{ */ $handle = @opendir($path); while ($entry = @readdir($handle) ) { @@ -220,12 +220,12 @@ class SeedDMS_Core_File { return @rmdir($path); } /* }}} */ - /** - * @param $sourcePath - * @param $targetPath - * @return bool - */ - static function copyDir($sourcePath, $targetPath) { /* {{{ */ + /** + * @param $sourcePath + * @param $targetPath + * @return bool + */ + static function copyDir($sourcePath, $targetPath) { /* {{{ */ if (mkdir($targetPath, 0777)) { $handle = @opendir($sourcePath); while ($entry = @readdir($handle) ) { @@ -247,26 +247,26 @@ class SeedDMS_Core_File { return true; } /* }}} */ - /** - * @param $sourcePath - * @param $targetPath - * @return bool - */ - static function moveDir($sourcePath, $targetPath) { /* {{{ */ - /** @noinspection PhpUndefinedFunctionInspection */ - if (!copyDir($sourcePath, $targetPath)) + /** + * @param $sourcePath + * @param $targetPath + * @return bool + */ + static function moveDir($sourcePath, $targetPath) { /* {{{ */ + /** @noinspection PhpUndefinedFunctionInspection */ + if (!copyDir($sourcePath, $targetPath)) return false; - /** @noinspection PhpUndefinedFunctionInspection */ - return removeDir($sourcePath); + /** @noinspection PhpUndefinedFunctionInspection */ + return removeDir($sourcePath); } /* }}} */ // code by Kioob (php.net manual) - /** - * @param $source - * @param bool $level - * @return bool|string - */ - static function gzcompressfile($source, $level=false) { /* {{{ */ + /** + * @param $source + * @param bool $level + * @return bool|string + */ + static function gzcompressfile($source, $level=false) { /* {{{ */ $dest=$source.'.gz'; $mode='wb'.$level; $error=false; diff --git a/SeedDMS_Core/package.xml b/SeedDMS_Core/package.xml index 68a71ded1..78b569462 100644 --- a/SeedDMS_Core/package.xml +++ b/SeedDMS_Core/package.xml @@ -12,11 +12,11 @@ uwe@steinmann.cx yes - 2018-11-23 - + 2020-04-02 + - 6.0.7 - 6.0.7 + 6.0.9 + 6.0.9 stable @@ -24,7 +24,7 @@ GPL License - ??? +- no changes, just keep same version as seeddms application @@ -80,6 +80,12 @@ + + + + + + @@ -1638,7 +1644,7 @@ remove deprecated methods SeedDMS_Core_Document::convert(), SeedDMS_Core_Documen - 2018-12-18 + 2019-04-04 5.1.10 @@ -1654,6 +1660,109 @@ fix php warning if workflow state doesn' have next transition add method SeedDMS_Core_DatabaseAccess::setLogFp() + + 2019-05-03 + + + 5.1.11 + 5.1.11 + + + stable + stable + + GPL License + +??? + + + + 2019-07-01 + + + 5.1.12 + 5.1.12 + + + stable + stable + + GPL License + +- parameter $orderby passed to SeedDMS_Core_Folder::getDocuments() and SeedDMS_Core_Folder::getSubFolders() can be a string, but only the first char is evaluated +- SeedDMS_Core_DMS::search() excepts parameters as array, added orderby +- add SeedDMS_Core_Folder::hasSubFolderByName() +- fix SeedDMS_Core_Folder::hasDocumentByName() which returned an int > 0 if documents + has been loaded before and even if the document searching for was not among them. +- add new method SeedDMS_Core_Folder::empty() + + + + 2019-09-06 + + + 5.1.13 + 5.1.13 + + + stable + stable + + GPL License + +- add decorators +- add new methods SeedDMS_Core_Document::isType(), SeedDMS_Core_Folder::isType(), SeedDMS_Core_DocumentContent::isType(). Use them instead of checking the class name. +- skip a fileType with just a '.' + + + + 2020-02-17 + + + 5.1.14 + 5.1.14 + + + stable + stable + + GPL License + +- speed up SeedDMS_Core_Folder::getSubFolders() SeedDMS_Core_Folder::getDocuments() by minimizing the number of sql queries. + + + + 2020-02-18 + + + 5.1.15 + 5.1.15 + + + stable + stable + + GPL License + +- no changes, just keep same version as seeddms application + + + + 2020-04-02 + + + 5.1.16 + 5.1.16 + + + stable + stable + + GPL License + +- no changes, just keep same version as seeddms application + + 2017-02-28 @@ -1804,5 +1913,41 @@ if currently in S_DRAFT status und no workflow, review, approval, or revision is pending. + + 2020-02-17 + + + 6.0.7 + 6.0.7 + + + stable + stable + + GPL License + +SeedDMS_Core_Document::getTimeline() returns revision only for latest content +add callback onSetStatus in SeedDMS_Core_DocumentContent::setStatus() +add new list type 'DueRevision' in SeedDMS_Core_DMS::getDocumentList() +a revision can also be started if some revisors have already reviewed the document +remove a user from all its process can also be used to set a new user + + + + 2020-03-02 + + + 6.0.8 + 6.0.8 + + + stable + stable + + GPL License + +- no changes, just keep same version as seeddms application + + diff --git a/SeedDMS_Lucene/Lucene/IndexedDocument.php b/SeedDMS_Lucene/Lucene/IndexedDocument.php index 237150097..df93e4a35 100644 --- a/SeedDMS_Lucene/Lucene/IndexedDocument.php +++ b/SeedDMS_Lucene/Lucene/IndexedDocument.php @@ -158,29 +158,31 @@ class SeedDMS_Lucene_IndexedDocument extends Zend_Search_Lucene_Document { } if($version && !$nocontent) { $path = $dms->contentDir . $version->getPath(); - $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(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($content['stderr']) { - $this->errormsg = $content['stderr']; - } - } catch (Exception $e) { } } } diff --git a/SeedDMS_Preview/Preview/Base.php b/SeedDMS_Preview/Preview/Base.php index f8723ee29..c8401bb48 100644 --- a/SeedDMS_Preview/Preview/Base.php +++ b/SeedDMS_Preview/Preview/Base.php @@ -50,6 +50,12 @@ class SeedDMS_Preview_Base { */ protected $xsendfile; + /** + * @var string $lastpreviewfile will be set to the file name of the last preview + * @access protected + */ + protected $lastpreviewfile; + function __construct($previewDir, $timeout=5, $xsendfile=true) { /* {{{ */ if(!is_dir($previewDir)) { if (!SeedDMS_Core_File::makeDir($previewDir)) { @@ -158,14 +164,14 @@ class SeedDMS_Preview_Base { return array_key_exists($mimetype, $this->converters) && $this->converters[$mimetype]; } /* }}} */ -/** - * Send a file from disk to the browser - * - * This function uses either readfile() or the xѕendfile apache module if - * it is installed. - * - * @param string $filename - */ + /** + * Send a file from disk to the browser + * + * This function uses either readfile() or the xѕendfile apache module if + * it is installed. + * + * @param string $filename + */ protected function sendFile($filename) { /* {{{ */ if($this->xsendfile && function_exists('apache_get_modules') && in_array('mod_xsendfile',apache_get_modules())) { header("X-Sendfile: ".$filename); @@ -177,5 +183,14 @@ class SeedDMS_Preview_Base { readfile($filename); } } /* }}} */ + + /** + * Return path of last created preview file + * + * @return string + */ + public function getPreviewFile() { /* {{{ */ + return $this->lastpreviewfile; + } /* }}} */ } diff --git a/SeedDMS_Preview/Preview/PdfPreviewer.php b/SeedDMS_Preview/Preview/PdfPreviewer.php index daae6a4ed..6ce557810 100644 --- a/SeedDMS_Preview/Preview/PdfPreviewer.php +++ b/SeedDMS_Preview/Preview/PdfPreviewer.php @@ -96,6 +96,7 @@ class SeedDMS_Preview_PdfPreviewer extends SeedDMS_Preview_Base { return false; if(!$target) $target = $this->previewDir.$dir.md5($infile); + $this->lastpreviewfile = $target.'.pdf'; if($target != '' && (!file_exists($target.'.pdf') || filectime($target.'.pdf') < filectime($infile))) { $cmd = ''; $mimeparts = explode('/', $mimetype, 2); @@ -110,6 +111,7 @@ class SeedDMS_Preview_PdfPreviewer extends SeedDMS_Preview_Base { try { self::execWithTimeout($cmd, $this->timeout); } catch(Exception $e) { + $this->lastpreviewfile = ''; return false; } } diff --git a/SeedDMS_Preview/Preview/Previewer.php b/SeedDMS_Preview/Preview/Previewer.php index b8df0ca1c..ba69b75a4 100644 --- a/SeedDMS_Preview/Preview/Previewer.php +++ b/SeedDMS_Preview/Preview/Previewer.php @@ -52,7 +52,7 @@ class SeedDMS_Preview_Previewer extends SeedDMS_Preview_Base { * @param integer $width width of preview image * @return string file name of preview image */ - protected function getFileName($object, $width) { /* {{{ */ + public function getFileName($object, $width) { /* {{{ */ if(!$object) return false; @@ -105,6 +105,7 @@ class SeedDMS_Preview_Previewer extends SeedDMS_Preview_Base { return false; if(!$target) $target = $this->previewDir.$dir.md5($infile).'-'.$width; + $this->lastpreviewfile = $target.'.png'; if($target != '' && (!file_exists($target.'.png') || filectime($target.'.png') < filectime($infile))) { $cmd = ''; $mimeparts = explode('/', $mimetype, 2); @@ -120,6 +121,7 @@ class SeedDMS_Preview_Previewer extends SeedDMS_Preview_Base { try { self::execWithTimeout($cmd, $this->timeout); } catch(Exception $e) { + $this->lastpreviewfile = ''; return false; } } diff --git a/SeedDMS_Preview/package.xml b/SeedDMS_Preview/package.xml index 9ecce9466..47a068c53 100644 --- a/SeedDMS_Preview/package.xml +++ b/SeedDMS_Preview/package.xml @@ -11,11 +11,11 @@ uwe@steinmann.cx yes - 2019-02-11 - + 2020-02-17 + - 1.2.10 - 1.2.10 + 1.3.0 + 1.3.0 stable @@ -23,10 +23,7 @@ GPL License -make sure list of converters is always an array -usage of mod_sendfile can be configured -new parameter for enabling/disabling xsendfile -fix creation of pdf preview if document content class is not SeedDMS_Core_DocumentContent +add new methode getPreviewFile() @@ -406,5 +403,22 @@ make sure list of converters is always an array usage of mod_sendfile can be configured + + 2019-02-11 + + + 1.2.10 + 1.2.10 + + + stable + stable + + GPL License + +new parameter for enabling/disabling xsendfile +fix creation of pdf preview if document content class is not SeedDMS_Core_DocumentContent + + diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php b/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php index fb87503b8..5e9fb08a1 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php @@ -152,29 +152,31 @@ class SeedDMS_SQLiteFTS_IndexedDocument extends SeedDMS_SQLiteFTS_Document { } if($version && !$nocontent) { $path = $dms->contentDir . $version->getPath(); - $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(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) { } - if($content['stderr']) { - $this->errormsg = $content['stderr']; - } - } catch (Exception $e) { } } } diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php b/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php index 1116616a6..7cac5d7e9 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php @@ -96,9 +96,10 @@ class SeedDMS_SQLiteFTS_Indexer { if(!$this->_conn) return false; - $sql = "INSERT INTO docs (docid, title, comment, keywords, category, owner, content, mimetype, origfilename, created) 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')).", ".time().")"; + $sql = "INSERT INTO docs (docid, title, comment, keywords, category, owner, content, mimetype, origfilename, created) 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')).", ".$doc->getFieldValue('created')/*time()*/.")"; $res = $this->_conn->exec($sql); if($res === false) { + return false; var_dump($this->_conn->errorInfo()); } return $res; diff --git a/SeedDMS_SQLiteFTS/package.xml b/SeedDMS_SQLiteFTS/package.xml index ed2256393..fdac846ba 100644 --- a/SeedDMS_SQLiteFTS/package.xml +++ b/SeedDMS_SQLiteFTS/package.xml @@ -11,11 +11,11 @@ uwe@steinmann.cx yes - 2018-04-11 + 2019-11-28 - 1.0.10 - 1.0.10 + 1.0.11 + 1.0.11 stable @@ -23,7 +23,8 @@ GPL License -IndexedDocument() remembers cmd and mimetype +Set 'created' in index to creation date of indexed content (was set to current +timestamp) @@ -226,5 +227,21 @@ allow conversion commands for mimetypes with wildcards execWithTimeout() reads data from stderr and saves it into error msg + + 2018-04-11 + + + 1.0.10 + 1.0.10 + + + stable + stable + + GPL License + +IndexedDocument() remembers cmd and mimetype + + diff --git a/TODO b/TODO index 8a9ea6cb8..830548653 100644 --- a/TODO +++ b/TODO @@ -6,8 +6,6 @@ which has not the expected result. Show message on doc info page if documents expects an action like review, approval, etc. -Import and export of a workflow as xml. - Find a way to make the workflows adjustable when used for a document. e.g. a workflow shall be used for a number of document but the users of a transtion has to be altered for each document. This is basically reusing diff --git a/conf/.htaccess b/conf/.htaccess index d774f51c9..2e473b4ba 100644 --- a/conf/.htaccess +++ b/conf/.htaccess @@ -1,6 +1,10 @@ # Make sure settings.xml can not be opened from outside! -#Redirect /conf/settings.xml /index.php - -Order allow,deny -Deny from all - +# Deny all requests from Apache 2.4+. + + Require all denied + + +# Deny all requests from Apache 2.0-2.2. + + Deny from all + diff --git a/conf/settings.xml.template b/conf/settings.xml.template index 452c847fe..40ab648eb 100644 --- a/conf/settings.xml.template +++ b/conf/settings.xml.template @@ -248,6 +248,7 @@ - enableVersionDeletion: allow to delete versions after approval - enableVersionModification: allow to modify versions after approval - enableDuplicateDocNames: allow duplicate names in a folder + - enableDuplicateSubFolderNames: allow duplicate names in a folder - enableOwnerRevApp: XXX - enableSelfRevApp: XXX - presetExpirationDate: XXX @@ -260,6 +261,7 @@ enableVersionDeletion = "true" enableVersionModification = "true" enableDuplicateDocNames = "true" + enableDuplicateSubFolderNames = "true" enableOwnerRevApp = "false" enableSelfRevApp = "false" presetExpirationDate = "" @@ -287,7 +289,7 @@ updateNotifyTime = "86400" extraPath = "" maxExecutionTime = "30" - cmdTimeout = "1" + cmdTimeout = "10" /> showConfigHeadline('settings_Edition'); ?> showConfigCheckbox('settings_strictFormCheck', 'strictFormCheck'); ?> +showConfigOption('settings_noDocumentFormFields', 'noDocumentFormFields', array('comment', 'keywords', 'categories', 'sequence', 'expires', 'version', 'version_comment', 'notification'), true, true); ?> showConfigText('settings_viewOnlineFileTypes', 'viewOnlineFileTypes', 'array'); ?> showConfigText('settings_editOnlineFileTypes', 'editOnlineFileTypes', 'array'); ?> showConfigCheckbox('settings_enableConverting', 'enableConverting'); ?> @@ -353,6 +357,9 @@ $this->showStartPaneContent('site', (!$currenttab || $currenttab == 'site')); showConfigText('settings_checkOutDir', 'checkOutDir'); ?> showConfigCheckbox('settings_createCheckOutDir', 'createCheckOutDir'); ?> showConfigText('settings_repositoryUrl', 'repositoryUrl'); ?> +showConfigText('settings_proxyUrl', 'proxyUrl'); ?> +showConfigText('settings_proxyUser', 'proxyUser'); ?> +showConfigText('settings_proxyUPassword', 'proxyPassword', 'password'); ?> showConfigCheckbox('settings_logFileEnable', 'logFileEnable'); ?> showConfigOption('settings_logFileRotation', 'logFileRotation', array('h'=>'hourly', 'd'=>'daily', 'm'=>'monthly'), false, true); ?> showConfigCheckbox('settings_enableLargeFileUpload', 'enableLargeFileUpload'); ?> @@ -429,10 +436,11 @@ $this->showStartPaneContent('site', (!$currenttab || $currenttab == 'site')); -- SETTINGS - ADVANCED - EDITION --> showConfigHeadline('settings_Edition'); ?> -showConfigOption('settings_workflowMode', 'workflowMode', array('traditional'=>'settings_workflowMode_valtraditional', 'traditional_only_approval'=>'settings_workflowMode_valtraditional_only_approval', 'advanced'=>'settings_workflowMode_valadvanced'), false, true); ?> +showConfigOption('settings_workflowMode', 'workflowMode', array('traditional'=>'settings_workflowMode_valtraditional', 'traditional_only_approval'=>'settings_workflowMode_valtraditional_only_approval', 'advanced'=>'settings_workflowMode_valadvanced', 'none'=>'settings_workflowMode_valnone'), false, true); ?> showConfigCheckbox('settings_enableReceiptWorkflow', 'enableReceiptWorkflow'); ?> +showConfigCheckbox('settings_enableReceiptReject', 'enableReceiptReject'); ?> showConfigCheckbox('settings_enableRevisionWorkflow', 'enableRevisionWorkflow'); ?> -showConfigCheckbox('settings_enableRevisionOnVoteReject', 'enableRevisionOnVoteReject'); ?> +showConfigCheckbox('settings_enableRevisionOneVoteReject', 'enableRevisionOneVoteReject'); ?> showConfigText('settings_versioningFileName', 'versioningFileName'); ?> showConfigText('settings_presetExpirationDate', 'presetExpirationDate'); ?> showConfigOption('settings_initialDocumentStatus', 'initialDocumentStatus', array(' '.S_RELEASED=>'settings_initialDocumentStatus_released', ' '.S_DRAFT=>'settings_initialDocumentStatus_draft'), false, true); ?> @@ -450,6 +458,7 @@ $this->showStartPaneContent('site', (!$currenttab || $currenttab == 'site')); showConfigCheckbox('settings_enableVersionDeletion', 'enableVersionDeletion'); ?> showConfigCheckbox('settings_enableVersionModification', 'enableVersionModification'); ?> showConfigCheckbox('settings_enableDuplicateDocNames', 'enableDuplicateDocNames'); ?> +showConfigCheckbox('settings_enableDuplicateSubFolderNames', 'enableDuplicateSubFolderNames'); ?> showConfigCheckbox('settings_overrideMimeType', 'overrideMimeType'); ?> showConfigCheckbox('settings_advancedAcl', 'advancedAcl'); ?> showConfigCheckbox('settings_removeFromDropFolder', 'removeFromDropFolder'); ?> @@ -474,6 +483,7 @@ $this->showStartPaneContent('site', (!$currenttab || $currenttab == 'site')); showConfigText('settings_updateNotifyTime', 'updateNotifyTime'); ?> showConfigText('settings_maxExecutionTime', 'maxExecutionTime'); ?> showConfigText('settings_cmdTimeout', 'cmdTimeout'); ?> +showConfigCheckbox('settings_enableDebugMode', 'enableDebugMode'); ?> showStartPaneContent('site', (!$currenttab || $currenttab == 'site')); -- SETTINGS - ADVANCED - DISPLAY --> $extconf) { + foreach($extmgr->getExtensionConfiguration() as $extname=>$extconf) { + if($this->hasHook('processConfig')) + $extconf = $this->callHook('processConfig', $extname, $extconf); if($extconf['config']) { - $this->showRawConfigHeadline("".$extconf['title']); + $this->showRawConfigHeadline("".'_extensions[$extname]["__disable__"] ? '1' : '').'" />'.$extconf['title']); foreach($extconf['config'] as $confkey=>$conf) { ob_start(); switch($conf['type']) { @@ -585,11 +597,14 @@ $this->showStartPaneContent('site', (!$currenttab || $currenttab == 'site')); } } break; + case 'hook': + echo $this->callHook('showConfig', $confkey, $extname, $extconf); + break; default: $this->showTextField("extensions[".$extname."][".$confkey."]", isset($settings->_extensions[$extname][$confkey]) ? $settings->_extensions[$extname][$confkey] : '', isset($conf['type']) ? $conf['type'] : '', isset($conf['placeholder']) ? $conf['placeholder'] : ''); } $html = ob_get_clean(); - $this->showConfigPlain($conf['title'], isset($conf['help']) ? $conf['help'] : '', $html); + $this->showConfigPlain($conf['title'], isset($conf['help']) ? $conf['help'] : '', $html); } } } diff --git a/views/bootstrap/class.SubstituteUser.php b/views/bootstrap/class.SubstituteUser.php index 7ac8a5f14..8cd982193 100644 --- a/views/bootstrap/class.SubstituteUser.php +++ b/views/bootstrap/class.SubstituteUser.php @@ -56,7 +56,7 @@ class SeedDMS_View_SubstituteUser extends SeedDMS_Bootstrap_Style { $this->contentHeading(getMLText("substitute_user")); ?> - + diff --git a/views/bootstrap/class.Tasks.php b/views/bootstrap/class.Tasks.php index 51d46cfb3..69c7fd178 100644 --- a/views/bootstrap/class.Tasks.php +++ b/views/bootstrap/class.Tasks.php @@ -43,6 +43,13 @@ class SeedDMS_View_Tasks extends SeedDMS_Bootstrap_Style { $enablerevisionworkflow = $this->params['enablerevisionworkflow']; $workflowmode = $this->params['workflowmode']; $tasksinmenu = $this->params['tasksinmenu']; + $tasks = array(); + if($workflowmode == 'traditional' || $workflowmode == 'traditional_only_approval') { + $tasks['approval'] = array(); + if($workflowmode == 'traditional') + $tasks['review'] = array(); + } elseif($workflowmode == 'advanced') + $tasks['workflow'] = array(); if($workflowmode == 'traditional' || $workflowmode == 'traditional_only_approval') if(!$tasksinmenu || in_array('approval', $tasksinmenu)) { @@ -227,14 +234,15 @@ class SeedDMS_View_Tasks extends SeedDMS_Bootstrap_Style { function menuTasks() { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; + $accessobject = $this->params['accessobject']; $tasks = $this->__myTasks(); if(!$tasks) return ''; $content = ''; -// $content .= " \n"; } -// $content .= " \n"; -// $content .= " \n"; + $content .= " \n"; + $content .= " \n"; echo $content; } /* }}} */ @@ -394,7 +402,8 @@ class SeedDMS_View_Tasks extends SeedDMS_Bootstrap_Style { if($folder = $dms->getFolder($folderid)) { $comment = $folder->getComment(); if (strlen($comment) > 150) $comment = substr($comment, 0, 147) . "..."; - $content .= "getID()."\" class=\"folder table-row-folder\" formtoken=\"".createFormKey('movefolder')."\">"; +// $content .= "getID()."\" class=\"folder table-row-folder\" formtoken=\"".createFormKey('movefolder')."\">"; + $content .= $this->folderListRowStart($folder); $content .= "\n"; $content .= "\n"; - $content .= "\n"; + //$content .= "\n"; + $content .= $this->folderListRowEnd($folder); $foldercount++; } } diff --git a/views/bootstrap/class.Timeline.php b/views/bootstrap/class.Timeline.php index c6498ec61..b76de7b3c 100644 --- a/views/bootstrap/class.Timeline.php +++ b/views/bootstrap/class.Timeline.php @@ -165,6 +165,7 @@ $(document).ready(function () { $this->printDeleteDocumentButtonJs(); $timelineurl = 'out.Timeline.php?action=data&fromdate='.date('Y-m-d', $from).'&todate='.date('Y-m-d', $to).'&skip='.urldecode(http_build_query(array('skip'=>$skip))); $this->printTimelineJs($timelineurl, 550, ''/*date('Y-m-d', $from)*/, ''/*date('Y-m-d', $to+1)*/, $skip); + $this->printClickDocumentJs(); } /* }}} */ function css() { /* {{{ */ diff --git a/views/bootstrap/class.TransmittalMgr.php b/views/bootstrap/class.TransmittalMgr.php index 6b38414f1..d966a2f62 100644 --- a/views/bootstrap/class.TransmittalMgr.php +++ b/views/bootstrap/class.TransmittalMgr.php @@ -301,7 +301,7 @@ $(document).ready( function() { } } print "\n
getID()."&showtree=".showtree()."\">imgpath."folder.png\" width=\"24\" height=\"24\" border=0>getID()."&showtree=".showtree()."\">" . htmlspecialchars($folder->getName()) . ""; if($comment) { @@ -404,7 +413,8 @@ class SeedDMS_View_Tasks extends SeedDMS_Bootstrap_Style { $content .= "\n"; $content .= ""; $content .= "
\n"; - print "getID()."\">".getMLText('download').""; + print "getID()."\">".getMLText('download').""; } } } /* }}} */ diff --git a/views/bootstrap/class.TriggerWorkflow.php b/views/bootstrap/class.TriggerWorkflow.php index b9a89bbd5..12091106e 100644 --- a/views/bootstrap/class.TriggerWorkflow.php +++ b/views/bootstrap/class.TriggerWorkflow.php @@ -79,7 +79,7 @@ $(document).ready(function() { $action = $transition->getAction(); $currentstate = $latestContent->getWorkflowState(); - $wkflog = $latestContent->getWorkflowLog(); + $wkflog = array_shift($latestContent->getWorkflowLog()); $workflow = $latestContent->getWorkflow(); $msg = "The document is currently in state: ".$currentstate->getName()."
"; diff --git a/views/bootstrap/class.UpdateDocument.php b/views/bootstrap/class.UpdateDocument.php index 8313b3c7f..2446e3015 100644 --- a/views/bootstrap/class.UpdateDocument.php +++ b/views/bootstrap/class.UpdateDocument.php @@ -142,6 +142,7 @@ console.log(element); $folder = $this->params['folder']; $document = $this->params['document']; $strictformcheck = $this->params['strictformcheck']; + $nodocumentformfields = $this->params['nodocumentformfields']; $enablelargefileupload = $this->params['enablelargefileupload']; $maxuploadsize = $this->params['maxuploadsize']; $enableadminrevapp = $this->params['enableadminrevapp']; @@ -239,6 +240,7 @@ console.log(element); $this->getDropFolderChooserHtml("form1") ); } + if(!$nodocumentformfields || !in_array('version_comment', $nodocumentformfields)) { $this->formField( getMLText("comment"), array( @@ -248,6 +250,8 @@ console.log(element); 'cols'=>80 ) ); + } + if(!$nodocumentformfields || !in_array('expires', $nodocumentformfields)) { if($presetexpiration) { if(!($expts = strtotime($presetexpiration))) $expts = false; @@ -274,6 +278,7 @@ console.log(element); getMLText("expires"), $this->getDateChooser(($expts ? date('Y-m-d', $expts) : ''), "expdate", $this->params['session']->getLanguage()) ); + } $attrdefs = $dms->getAllAttributeDefinitions(array(SeedDMS_Core_AttributeDefinition::objtype_documentcontent, SeedDMS_Core_AttributeDefinition::objtype_all)); if($attrdefs) { foreach($attrdefs as $attrdef) { @@ -353,7 +358,7 @@ console.log(element); ); } $this->warningMsg(getMLText("add_doc_workflow_warning")); - } else { + } elseif($workflowmode == 'traditional' || $workflowmode == 'traditional_only_approval') { $docAccess = $document->getReadAccessList($enableadminrevapp, $enableownerrevapp); if($workflowmode == 'traditional') { $this->contentSubHeading(getMLText("assign_reviewers")); @@ -474,7 +479,7 @@ console.log(element); } } } - $fieldwrap = array(); + $fieldwrap = array('', ''); if($tmp) { $fieldwrap = array('', $this->getSelectPresetButtonHtml("GrpReviewers", $tmp)); } @@ -641,7 +646,7 @@ console.log(element); } } } - $fieldwrap = array(); + $fieldwrap = array('', ''); if($tmp) { $fieldwrap = array('', $this->getSelectPresetButtonHtml("GrpApprovers", $tmp)); } diff --git a/views/bootstrap/class.UserList.php b/views/bootstrap/class.UserList.php index 263922b07..4cc9317f6 100644 --- a/views/bootstrap/class.UserList.php +++ b/views/bootstrap/class.UserList.php @@ -31,6 +31,19 @@ require_once("class.Bootstrap.php"); */ class SeedDMS_View_UserList extends SeedDMS_Bootstrap_Style { + function js() { /* {{{ */ +?> + $(document).ready(function(){ + $("#myInput").on("keyup", function() { + var value = $(this).val().toLowerCase(); + $("#myTable tbody tr").filter(function() { + $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1) + }); + }); + }); +params['dms']; $user = $this->params['user']; @@ -38,6 +51,7 @@ class SeedDMS_View_UserList extends SeedDMS_Bootstrap_Style { $httproot = $this->params['httproot']; $quota = $this->params['quota']; $pwdexpiration = $this->params['pwdexpiration']; + $accessobject = $this->params['accessobject']; $this->htmlStartPage(getMLText("admin_tools")); $this->globalNavigation(); @@ -48,7 +62,8 @@ class SeedDMS_View_UserList extends SeedDMS_Bootstrap_Style { $sessionmgr = new SeedDMS_SessionMgr($dms->getDB()); ?> - + +
"; echo ""; echo ""; echo ""; + } elseif(is_string($arr)) { + echo $arr; } else { $this->printAttribute($attribute); } @@ -387,8 +394,8 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { if(!$showfullpreview) return; - $accessop = $this->params['accessobject']; - if($accessop->check_controller_access('ViewOnline', array('action'=>'version'))) { + $accessobject = $this->params['accessobject']; + if($accessobject->check_controller_access('ViewOnline', array('action'=>'version'))) { $latestContent = $this->callHook('documentLatestContent', $document); if($latestContent === null) $latestContent = $document->getLatestContent(); @@ -416,6 +423,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { case 'video/avi': case 'video/msvideo': case 'video/x-msvideo': + case 'video/x-matroska': $this->contentHeading(getMLText("preview")); ?> "; foreach($statuslog as $entry) { if($suser = $dms->getUser($entry['userID'])) - $fullname = $suser->getFullName(); + $fullname = htmlspecialchars($suser->getFullName()); else $fullname = "--"; - echo "\n"; + echo "\n"; } print "\n
"; - if($this->check_access(array('UsrMgr', 'RemoveUser'))) { + if($accessobject->check_view_access(array('UsrMgr', 'RemoveUser'))) { echo "
"; echo $this->html_link('UsrMgr', array('userid'=>$currUser->getID()), array(), '', false); echo $this->html_link('RemoveUser', array('userid'=>$currUser->getID()), array(), '', false); diff --git a/views/bootstrap/class.UsrMgr.php b/views/bootstrap/class.UsrMgr.php index e6929797e..2a1468af6 100644 --- a/views/bootstrap/class.UsrMgr.php +++ b/views/bootstrap/class.UsrMgr.php @@ -77,6 +77,7 @@ $(document).ready( function() { }); $( "#selector" ).change(function() { $('div.ajax').trigger('update', {userid: $(this).val()}); + window.history.pushState({"html":"","pageTitle":""},"", '../out/out.UsrMgr.php?userid=' + $(this).val()); }); }); params['quota']; $undeluserids = $this->params['undeluserids']; $enableemail = $this->params['enableemail']; + $accessobject = $this->params['accessobject']; if($seluser) { ?> @@ -205,7 +207,7 @@ $(document).ready( function() {
contentContainerStart(); ?> -check_view_access($this, array('action'=>'form'))) { ?> +check_view_access($this, array('action'=>'form'))) { ?>
getID()."\"" : "") ?>>
diff --git a/views/bootstrap/class.ViewDocument.php b/views/bootstrap/class.ViewDocument.php index a8265bd58..6192f8238 100644 --- a/views/bootstrap/class.ViewDocument.php +++ b/views/bootstrap/class.ViewDocument.php @@ -200,6 +200,8 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { } $this->printDocumentChooserJs("form1"); $this->printDeleteDocumentButtonJs(); + /* Add js for catching click on document in one page mode */ + $this->printClickDocumentJs(); } /* }}} */ function documentInfos() { /* {{{ */ @@ -210,7 +212,10 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { $checkoutdir = $this->params['checkOutDir']; $this->contentHeading(getMLText("document_infos")); - if($info = $document->getCheckOutInfo()) { + $txt = $this->callHook('checkOutInfo', $document); + if(is_string($txt)) { + echo $txt; + } elseif($info = $document->getCheckOutInfo()) { echo "
"; $session = $this->params['session']; if($session->getSu()) { @@ -359,6 +364,8 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { echo "
".$arr[0].":".$arr[1]."
".$entry['date']."".getOverallStatusText($entry['status'])."".$fullname."".$entry['comment']."
".$entry['date']."".getOverallStatusText($entry['status'])."".$fullname."".htmlspecialchars($entry['comment'])."
\n"; $this->contentContainerEnd(); @@ -806,8 +820,8 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { echo "".$wkflog->getDate().""; echo "".$wkflog->getTransition()->getAction()->getName().""; $loguser = $wkflog->getUser(); - echo "".$loguser->getFullName().""; - echo "".$wkflog->getComment().""; + echo "".htmlspecialchars($loguser->getFullName()).""; + echo "".htmlspecialchars($wkflog->getComment()).""; echo ""; } print "\n\n"; @@ -825,17 +839,17 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style {
"; - print "
"; -// $this->contentContainerStart(); - print "".getMLText('reviewers').""; - print "\n"; - /* Just check fo an exting reviewStatus, even workflow mode is set * to traditional_only_approval. There may be old documents which * are still in S_DRAFT_REV. */ if (/*$workflowmode != 'traditional_only_approval' &&*/ is_array($reviewStatus) && count($reviewStatus)>0) { + print "
"; +// $this->contentContainerStart(); + print "".getMLText('reviewers').""; + print "
\n"; + print "\n"; print "\n"; print "\n"; @@ -893,7 +907,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { print htmlspecialchars($r["comment"]); if($r['file']) { echo "
"; - if($accessop->check_controller_access('Download', array('action'=>'run'))) { + if($accessobject->check_controller_access('Download', array('action'=>'run'))) { echo " ".getMLText('download').""; } } @@ -903,11 +917,11 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { if($accesserr) echo "
  • ".$accesserr."
  • "; - if($accessop->mayReview($document)) { + if($accessobject->mayReview($document)) { if ($is_reviewer) { if ($r["status"]==0) { print "
  • ".$this->html_link('ReviewDocument', array('documentid'=>$documentid, 'version'=>$latestContent->getVersion(), 'reviewid'=>$r['reviewID']), array('class'=>'btn btn-mini'), getMLText("add_review"), false, true)."
  • "; - } elseif ($accessop->mayUpdateReview($document, $updateUser) && (($r["status"]==1)||($r["status"]==-1))){ + } elseif ($accessobject->mayUpdateReview($document, $updateUser) && (($r["status"]==1)||($r["status"]==-1))){ print "
  • ".$this->html_link('ReviewDocument', array('documentid'=>$documentid, 'version'=>$latestContent->getVersion(), 'reviewid'=>$r['reviewID']), array('class'=>'btn btn-mini'), getMLText("edit"), false, true)."
  • "; } } @@ -917,11 +931,11 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { print "\n"; } } - } - print "
    ".getMLText("name")."".getMLText("last_update").", ".getMLText("comment")."
    "; + print ""; // $this->contentContainerEnd(); - print "
    "; + print "
    "; + } print "
    "; // $this->contentContainerStart(); print "".getMLText('approvers').""; @@ -985,7 +999,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { print htmlspecialchars($a["comment"]); if($a['file']) { echo "
    "; - if($accessop->check_controller_access('Download', array('action'=>'run'))) { + if($accessobject->check_controller_access('Download', array('action'=>'run'))) { echo " ".getMLText('download').""; } } @@ -995,11 +1009,11 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { if($accesserr) echo "
  • ".$accesserr."
  • "; - if($accessop->mayApprove($document)) { + if($accessobject->mayApprove($document)) { if ($is_approver) { if ($a['status'] == 0) { print "
  • ".$this->html_link('ApproveDocument', array('documentid'=>$documentid, 'version'=>$latestContent->getVersion(), 'approveid'=>$a['approveID']), array('class'=>'btn btn-mini'), getMLText("add_approval"), false, true)."
  • "; - } elseif ($accessop->mayUpdateApproval($document, $updateUser) && (($a["status"]==1)||($a["status"]==-1))){ + } elseif ($accessobject->mayUpdateApproval($document, $updateUser) && (($a["status"]==1)||($a["status"]==-1))){ print "
  • ".$this->html_link('ApproveDocument', array('documentid'=>$documentid, 'version'=>$latestContent->getVersion(), 'approveid'=>$a['approveID']), array('class'=>'btn btn-mini'), getMLText("edit"), false, true)."
  • "; } } @@ -1044,7 +1058,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style {
    " id="workflow"> "; - if ($user_is_involved && $this->check_access('WorkflowGraph')) + if ($user_is_involved && $accessobject->check_view_access('WorkflowGraph')) echo "
    "; else echo "
    "; @@ -1070,11 +1084,11 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { } } - echo "

    ".$workflow->getName()."

    "; + echo "

    ".htmlspecialchars($workflow->getName())."

    "; if($parentworkflow = $latestContent->getParentWorkflow()) { - echo "

    Sub workflow of '".$parentworkflow->getName()."'

    "; + echo "

    Sub workflow of '".htmlspecialchars($parentworkflow->getName())."'

    "; } - echo "
    ".getMLText('current_state').": ".$workflowstate->getName()."
    "; + echo "
    ".getMLText('current_state').": ".htmlspecialchars($workflowstate->getName())."
    "; echo "\n"; echo ""; echo ""; @@ -1098,7 +1112,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { echo "
    ".getMLText('next_state').":"; foreach($transusers as $transuser) { $u = $transuser->getUser(); - echo $u->getFullName(); + echo htmlspecialchars($u->getFullName()); if($document->getAccessMode($u) < M_READ) { echo " (no access)"; } @@ -1116,7 +1130,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { $g = $transgroup->getGroup(); echo getMLText('at_least_n_users_of_group', array("number_of_users" => $transgroup->getNumOfUsers(), - "group" => $g->getName())); + "group" => htmlspecialchars($g->getName()))); if ($document->getGroupAccessMode($g) < M_READ) { echo " (no access)"; } @@ -1146,10 +1160,10 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { $wkflogs = $latestContent->getWorkflowLog($transition); foreach($wkflogs as $wkflog) { $loguser = $wkflog->getUser(); - echo $loguser->getFullName()." ("; + echo htmlspecialchars($loguser->getFullName())." ("; $names = array(); foreach($loguser->getGroups() as $loggroup) { - $names[] = $loggroup->getName(); + $names[] = htmlspecialchars($loggroup->getName()); } echo implode(", ", $names); echo ") - "; @@ -1245,7 +1259,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { } $this->contentContainerEnd(); echo ""; - if ($user_is_involved && $this->check_access('WorkflowGraph')) { + if ($user_is_involved && $accessobject->check_view_access('WorkflowGraph')) { echo "
    "; ?> @@ -1334,11 +1348,11 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { print "
      "; if($accesserr) echo "
    • ".$accesserr."
    • "; - if($accessop->mayReceipt($document)) { + if($accessobject->mayReceipt($document)) { if ($is_recipient) { if($r["status"]==0) { print "
    • ".$this->html_link('ReceiptDocument', array('documentid'=>$documentid, 'version'=>$latestContent->getVersion(), 'receiptid'=>$r['receiptID']), array('class'=>'btn btn-mini'), getMLText("add_receipt"), false, true)."
    • "; - } elseif ($accessop->mayUpdateReceipt($document, $updateUser) && (($r["status"]==1)||($r["status"]==-1))) { + } elseif ($accessobject->mayUpdateReceipt($document, $updateUser) && (($r["status"]==1 && $enablereceiptreject)||($r["status"]==-1))) { print "
    • ".$this->html_link('ReceiptDocument', array('documentid'=>$documentid, 'version'=>$latestContent->getVersion(), 'receiptid'=>$r['receiptID']), array('class'=>'btn btn-mini'), getMLText("edit"), false, true)."
    • "; } } @@ -1352,7 +1366,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style {
    contentContainerEnd(); - if($accessop->check_view_access('ViewDocument', array('action'=>'receptionBar'))/* $user->isAdmin() || $user->getId() == $document->getOwner()->getId()*/) { + if($accessobject->check_view_access('ViewDocument', array('action'=>'receptionBar'))/* $user->isAdmin() || $user->getId() == $document->getOwner()->getId()*/) { /* Do not count entries '-2' as they are removed userѕ */ $totalreceipts = $stat['-1'] + $stat['0'] + $stat['1']; ?> @@ -1450,14 +1464,17 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Bootstrap_Style { print "".$reqName."\n"; print "
    • ".$r["date"]."
    • "; /* $updateUser is the user who has done the revision */ - $updateUser = $dms->getUser($r["userID"]); - print "
    • ".(is_object($updateUser) ? htmlspecialchars($updateUser->getFullName()." (".$updateUser->getLogin().")") : "unknown user id '".$r["userID"]."'")."
    "; + if($r['status'] != 0) { + $updateUser = $dms->getUser($r["userID"]); + print "
  • ".(is_object($updateUser) ? htmlspecialchars($updateUser->getFullName()." (".$updateUser->getLogin().")") : "unknown user id '".$r["userID"]."'")."
  • "; + } + print ""; print "".htmlspecialchars($r["comment"])."\n"; print "".getRevisionStatusText($r["status"])."\n"; print "
    callHook('postContent'); $this->contentEnd(); $this->htmlEndPage(); } /* }}} */ diff --git a/views/bootstrap/class.ViewFolder.php b/views/bootstrap/class.ViewFolder.php index 722b6799c..f8474525f 100644 --- a/views/bootstrap/class.ViewFolder.php +++ b/views/bootstrap/class.ViewFolder.php @@ -36,6 +36,16 @@ require_once("SeedDMS/Preview.php"); */ class SeedDMS_View_ViewFolder extends SeedDMS_Bootstrap_Style { + function data() { /* {{{ */ + $dms = $this->params['dms']; + $user = $this->params['user']; + $folder = $this->params['folder']; + + $jsondata = array('name'=>$folder->getName()); + header('Content-Type: application/json'); + echo json_encode($jsondata); + } /* }}} */ + function getAccessModeText($defMode) { /* {{{ */ switch($defMode) { case M_NONE: @@ -83,20 +93,40 @@ class SeedDMS_View_ViewFolder extends SeedDMS_Bootstrap_Style { } } /* }}} */ - function js() { /* {{{ */ + public function subtree() { /* {{{ */ + $user = $this->params['user']; + $node = $this->params['node']; + $orderby = $this->params['orderby']; + + $this->printNewTreeNavigationSubtree($node->getID(), 0, $orderby); + } /* }}} */ + + public function js() { /* {{{ */ $user = $this->params['user']; $folder = $this->params['folder']; $orderby = $this->params['orderby']; + $orderdir = (isset($orderby[1]) ? ($orderby[1] == 'd' ? 'desc' : 'asc') : 'asc'); $expandFolderTree = $this->params['expandFolderTree']; $enableDropUpload = $this->params['enableDropUpload']; $maxItemsPerPage = $this->params['maxItemsPerPage']; $showtree = $this->params['showtree']; + $onepage = $this->params['onepage']; + $sitename = trim(strip_tags($this->params['sitename'])); header('Content-Type: application/javascript; charset=UTF-8'); - parent::jsTranslations(array('cancel', 'splash_move_document', 'confirm_move_document', 'move_document', 'splash_move_folder', 'confirm_move_folder', 'move_folder')); + parent::jsTranslations(array('cancel', 'splash_move_document', 'confirm_move_document', 'move_document', 'confirm_transfer_link_document', 'transfer_content', 'link_document', 'splash_move_folder', 'confirm_move_folder', 'move_folder')); ?> +seeddms_folder = getID() ?>; function folderSelected(id, name) { + window.location = '../out/out.ViewFolder.php?folderid=' + id; + + seeddms_folder = id; + title_prefix = "0 ? $sitename : "SeedDMS") ?>"; + $('div.ajax').trigger('update', {folderid: id, orderby: ''}); + document.title = title_prefix+": "+name; + window.history.pushState({"html":"","pageTitle":title_prefix+": "+name},"", '../out/out.ViewFolder.php?folderid=' + id); + } function loadMoreObjects(element, limit) { @@ -130,9 +160,44 @@ $(window).scroll(function() { loadMoreObjects($('#loadmore'), $('#loadmore').data('limit')); } }); -$('#loadmore').click(function(e) { +$('body').on('click', '#loadmore', function(e) { loadMoreObjects($(this), $(this).data('all')); }); + + + +window.onpopstate = function(event) { +console.log("location: " + document.location + ", state: " + JSON.stringify(event.state)); +console.log(JSON.stringify(event.state)); + window.location = document.location; +}; +/* catch click on 'goto parent button' */ +$('body').on('click', '#goto-parent', function(ev) { + attr_id = $(ev.currentTarget).data('parentid'); + folderSelected(attr_id, ''); + $([document.documentElement, document.body]).animate({ + scrollTop: 200 + }, 200); +}); +/* catch click on a folder row in the list folders and documents */ +$('body').on('click', '[id^=\"table-row-folder\"] td:nth-child(2)', function(ev) { + attr_id = $(ev.currentTarget).parent().attr('id').split('-')[3]; + folderSelected(attr_id, ''); + $([document.documentElement, document.body]).animate({ + scrollTop: 200 + }, 200); +}); +printClickDocumentJs(); +?> +$('body').on('click', '.order-btn', function(ev) { + ev.preventDefault(); + var element = $(this); + var orderby = element.data('orderby'); + $("div.ajax[data-action='folderList']").trigger('update', {folderid: seeddms_folder, orderby: orderby}); +}); printDeleteDocumentButtonJs(); } /* }}} */ - function entries() { /* {{{ */ + function folderInfos() { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; $folder = $this->params['folder']; - $orderby = $this->params['orderby']; - $cachedir = $this->params['cachedir']; - $previewwidth = $this->params['previewWidthList']; - $previewconverters = $this->params['previewConverters']; - $timeout = $this->params['timeout']; - $xsendfile = $this->params['xsendfile']; - $offset = $this->params['offset']; - $limit = $this->params['limit']; - header('Content-Type: application/json'); - - $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout, $xsendfile); - $previewer->setConverters($previewconverters); - - $subFolders = $this->callHook('folderGetSubFolders', $folder, $orderby); - if($subFolders === null) - $subFolders = $folder->getSubFolders($orderby); - $subFolders = SeedDMS_Core_DMS::filterAccess($subFolders, $user, M_READ); - $documents = $this->callHook('folderGetDocuments', $folder, $orderby); - if($documents === null) - $documents = $folder->getDocuments($orderby); - $documents = SeedDMS_Core_DMS::filterAccess($documents, $user, M_READ); - - $content = ''; - if ((count($subFolders) > 0)||(count($documents) > 0)){ - $i = 0; // counts all entries - $j = 0; // counts only returned entries - foreach($subFolders as $subFolder) { - if($i >= $offset && $j < $limit) { - $txt = $this->callHook('folderListItem', $subFolder, 'viewfolder'); - if(is_string($txt)) - $content .= $txt; - else { - $content .= $this->folderListRow($subFolder); - } - $j++; - } - $i++; - } - - if($subFolders && $documents) { - if(($j && $j < $limit) || ($offset + $limit == $i)) { - $txt = $this->callHook('folderListSeparator', $folder); - if(is_string($txt)) - $content .= $txt; - } - } - - foreach($documents as $document) { - if($i >= $offset && $j < $limit) { - $document->verifyLastestContentExpriry(); - $txt = $this->callHook('documentListItem', $document, $previewer, false, 'viewfolder'); - if(is_string($txt)) - $content .= $txt; - else { - $content .= $this->documentListRow($document, $previewer); - } - $j++; - } - $i++; - } - - echo json_encode(array('error'=>0, 'count'=>$i-($offset+$limit), 'html'=>$content)); - } - - } /* }}} */ - - function show() { /* {{{ */ - $dms = $this->params['dms']; - $user = $this->params['user']; - $folder = $this->params['folder']; - $orderby = $this->params['orderby']; - $enableFolderTree = $this->params['enableFolderTree']; - $enableClipboard = $this->params['enableclipboard']; - $enableDropUpload = $this->params['enableDropUpload']; - $expandFolderTree = $this->params['expandFolderTree']; - $showtree = $this->params['showtree']; - $cachedir = $this->params['cachedir']; - $workflowmode = $this->params['workflowmode']; - $enableRecursiveCount = $this->params['enableRecursiveCount']; - $maxRecursiveCount = $this->params['maxRecursiveCount']; - $maxItemsPerPage = $this->params['maxItemsPerPage']; - $incItemsPerPage = $this->params['incItemsPerPage']; - $previewwidth = $this->params['previewWidthList']; - $previewconverters = $this->params['previewConverters']; - $timeout = $this->params['timeout']; - $xsendfile = $this->params['xsendfile']; - - $folderid = $folder->getId(); - - $this->htmlAddHeader(''."\n", 'js'); - - echo $this->callHook('startPage'); - $this->htmlStartPage(getMLText("folder_title", array("foldername" => htmlspecialchars($folder->getName())))); - - $this->globalNavigation($folder); - $this->contentStart(); - $txt = $this->callHook('folderMenu', $folder); - if(is_string($txt)) - echo $txt; - else { - $this->pageNavigation($this->getFolderPathHTML($folder), "view_folder", $folder); - } - - $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout, $xsendfile); - $previewer->setConverters($previewconverters); - - echo $this->callHook('preContent'); - - echo "
    \n"; - - // dynamic columns - left column removed if no content and right column then fills span12. - if (!($enableFolderTree || $enableClipboard)) { - $LeftColumnSpan = 0; - $RightColumnSpan = 12; - } else { - $LeftColumnSpan = 4; - $RightColumnSpan = 8; - } - if ($LeftColumnSpan > 0) { - echo "
    \n"; - if ($enableFolderTree) { - if ($showtree==1){ - $this->contentHeading("", true); - $this->contentContainerStart(); - /* - * access expandFolderTree with $this->params because it can - * be changed by preContent hook. - */ - $this->printNewTreeNavigationHtml($folderid, M_READ, 0, '', ($this->params['expandFolderTree'] == 1) ? -1 : 3, $orderby); - $this->contentContainerEnd(); - } else { - $this->contentHeading("", true); - } - } - - echo $this->callHook('leftContent'); - - if ($enableClipboard) $this->printClipboard($this->params['session']->getClipboard(), $previewer); - - echo "
    \n"; - } - echo "
    \n"; - - if ($enableDropUpload && $folder->getAccessMode($user) >= M_READWRITE) { - echo "
    "; - echo "
    "; - } $txt = $this->callHook('folderInfo', $folder); if(is_string($txt)) echo $txt; @@ -385,8 +303,10 @@ $('#loadmore').click(function(e) { if(is_array($arr)) { echo ""; echo "".$arr[0].":"; - echo "".$arr[1].""; + echo "".$arr[1].":"; echo ""; + } elseif(is_string($arr)) { + echo $arr; } else { $this->printAttribute($attribute); } @@ -396,21 +316,26 @@ $('#loadmore').click(function(e) { echo "\n"; $this->contentContainerEnd(); } - if ($enableDropUpload && $folder->getAccessMode($user) >= M_READWRITE) { - echo "
    "; - echo "
    "; - $this->contentHeading(getMLText("dropupload"), true); -// $this->addFooterJS("SeedDMSUpload.setUrl('../op/op.Ajax.php');"); -// $this->addFooterJS("SeedDMSUpload.setAbortBtnLabel('".getMLText("cancel")."');"); -// $this->addFooterJS("SeedDMSUpload.setEditBtnLabel('".getMLText("edit_document_props")."');"); -// $this->addFooterJS("SeedDMSUpload.setMaxFileSize(".SeedDMS_Core_File::parse_filesize(ini_get("upload_max_filesize")).");"); -// $this->addFooterJS("SeedDMSUpload.setMaxFileSizeMsg('".getMLText("uploading_maxsize")."');"); -?> -
    -"; - echo "
    "; - } + } /* }}} */ + + function folderList() { /* {{{ */ + $dms = $this->params['dms']; + $user = $this->params['user']; + $folder = $this->params['folder']; + $folderid = $folder->getId(); + $orderby = $this->params['orderby']; + $orderdir = (isset($orderby[1]) ? ($orderby[1] == 'd' ? 'desc' : 'asc') : 'asc'); + $cachedir = $this->params['cachedir']; + $maxItemsPerPage = $this->params['maxItemsPerPage']; + $incItemsPerPage = $this->params['incItemsPerPage']; + $previewwidth = $this->params['previewWidthList']; + $previewconverters = $this->params['previewConverters']; + $timeout = $this->params['timeout']; + $xsendfile = $this->params['xsendfile']; + $onepage = $this->params['onepage']; + + $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout, $xsendfile); + $previewer->setConverters($previewconverters); $txt = $this->callHook('listHeader', $folder); if(is_string($txt)) @@ -418,28 +343,34 @@ $('#loadmore').click(function(e) { else $this->contentHeading(getMLText("folder_contents")); - $subFolders = $this->callHook('folderGetSubFolders', $folder, $orderby); + $subFolders = $this->callHook('folderGetSubFolders', $folder, $orderby[0], $orderdir); if($subFolders === null) - $subFolders = $folder->getSubFolders($orderby); + $subFolders = $folder->getSubFolders($orderby[0], $orderdir); $subFolders = SeedDMS_Core_DMS::filterAccess($subFolders, $user, M_READ); - $documents = $this->callHook('folderGetDocuments', $folder, $orderby); + $documents = $this->callHook('folderGetDocuments', $folder, $orderby[0], $orderdir); if($documents === null) - $documents = $folder->getDocuments($orderby); + $documents = $folder->getDocuments($orderby[0], $orderdir); $documents = SeedDMS_Core_DMS::filterAccess($documents, $user, M_READ); + $parent = $onepage ? $folder->getParent() : null; $txt = $this->callHook('folderListPreContent', $folder, $subFolders, $documents); if(is_string($txt)) echo $txt; $i = 0; if ((count($subFolders) > 0)||(count($documents) > 0)){ - $txt = $this->callHook('folderListHeader', $folder, $orderby); + $txt = $this->callHook('folderListHeader', $folder, $orderby, $orderdir); if(is_string($txt)) echo $txt; else { print ""; print "\n\n"; - print "\n"; - print "\n"; + print "\n"; + print "\n"; + // print "\n"; print "\n"; print "\n"; print "\n\n\n"; @@ -447,7 +378,7 @@ $('#loadmore').click(function(e) { foreach($subFolders as $subFolder) { if(!$maxItemsPerPage || $i < $maxItemsPerPage) { - $txt = $this->callHook('folderListItem', $subFolder, 'viewfolder'); + $txt = $this->callHook('folderListItem', $subFolder, false, 'viewfolder'); if(is_string($txt)) echo $txt; else { @@ -493,6 +424,208 @@ $('#loadmore').click(function(e) { if(is_string($txt)) echo $txt; + } /* }}} */ + + function navigation() { /* {{{ */ + $dms = $this->params['dms']; + $user = $this->params['user']; + $folder = $this->params['folder']; + + $txt = $this->callHook('folderMenu', $folder); + if(is_string($txt)) + echo $txt; + else { + $this->pageNavigation($this->getFolderPathHTML($folder), "view_folder", $folder); + } + + echo $this->callHook('preContent'); + } /* }}} */ + + function dropUpload() { /* {{{ */ + $dms = $this->params['dms']; + $user = $this->params['user']; + $folder = $this->params['folder']; + + $this->contentHeading(getMLText("dropupload"), true); +?> +
    +params['dms']; + $user = $this->params['user']; + $folder = $this->params['folder']; + $orderby = $this->params['orderby']; + $orderdir = (isset($orderby[1]) ? ($orderby[1] == 'd' ? 'desc' : 'asc') : 'asc'); + $cachedir = $this->params['cachedir']; + $previewwidth = $this->params['previewWidthList']; + $previewconverters = $this->params['previewConverters']; + $timeout = $this->params['timeout']; + $xsendfile = $this->params['xsendfile']; + $offset = $this->params['offset']; + $limit = $this->params['limit']; + + header('Content-Type: application/json'); + + $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout, $xsendfile); + $previewer->setConverters($previewconverters); + + $subFolders = $this->callHook('folderGetSubFolders', $folder, $orderby[0]); + if($subFolders === null) + $subFolders = $folder->getSubFolders($orderby[0], $orderdir); + $subFolders = SeedDMS_Core_DMS::filterAccess($subFolders, $user, M_READ); + $documents = $this->callHook('folderGetDocuments', $folder, $orderby[0]); + if($documents === null) + $documents = $folder->getDocuments($orderby[0], $orderdir); + $documents = SeedDMS_Core_DMS::filterAccess($documents, $user, M_READ); + + $content = ''; + if ((count($subFolders) > 0)||(count($documents) > 0)){ + $i = 0; // counts all entries + $j = 0; // counts only returned entries + foreach($subFolders as $subFolder) { + if($i >= $offset && $j < $limit) { + $txt = $this->callHook('folderListItem', $subFolder, false, 'viewfolder'); + if(is_string($txt)) + $content .= $txt; + else { + $content .= $this->folderListRow($subFolder); + } + $j++; + } + $i++; + } + + if($subFolders && $documents) { + if(($j && $j < $limit) || ($offset + $limit == $i)) { + $txt = $this->callHook('folderListSeparator', $folder); + if(is_string($txt)) + $content .= $txt; + } + } + + foreach($documents as $document) { + if($i >= $offset && $j < $limit) { + $document->verifyLastestContentExpriry(); + $txt = $this->callHook('documentListItem', $document, $previewer, false, 'viewfolder'); + if(is_string($txt)) + $content .= $txt; + else { + $content .= $this->documentListRow($document, $previewer); + } + $j++; + } + $i++; + } + + echo json_encode(array('error'=>0, 'count'=>$i-($offset+$limit), 'html'=>$content)); + } + + } /* }}} */ + + function show() { /* {{{ */ + $dms = $this->params['dms']; + $user = $this->params['user']; + $folder = $this->params['folder']; + $orderby = $this->params['orderby']; + $orderdir = (isset($orderby[1]) ? ($orderby[1] == 'd' ? 'desc' : 'asc') : 'asc'); + $enableFolderTree = $this->params['enableFolderTree']; + $enableClipboard = $this->params['enableclipboard']; + $enableDropUpload = $this->params['enableDropUpload']; + $expandFolderTree = $this->params['expandFolderTree']; + $showtree = $this->params['showtree']; + $cachedir = $this->params['cachedir']; + $enableRecursiveCount = $this->params['enableRecursiveCount']; + $maxRecursiveCount = $this->params['maxRecursiveCount']; + $maxItemsPerPage = $this->params['maxItemsPerPage']; + $incItemsPerPage = $this->params['incItemsPerPage']; + $previewwidth = $this->params['previewWidthList']; + $previewconverters = $this->params['previewConverters']; + $timeout = $this->params['timeout']; + $xsendfile = $this->params['xsendfile']; + + $folderid = $folder->getId(); + $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout, $xsendfile); + $previewer->setConverters($previewconverters); + + $this->htmlAddHeader(''."\n", 'js'); + + echo $this->callHook('startPage'); + $this->htmlStartPage(getMLText("folder_title", array("foldername" => htmlspecialchars($folder->getName())))); + $this->globalNavigation($folder); + $this->contentStart(); + +// $this->navigation(); +?> +
    getID()."\"" : "") ?>>
    +\n"; + + // dynamic columns - left column removed if no content and right column then fills span12. + if (!($enableFolderTree || $enableClipboard)) { + $LeftColumnSpan = 0; + $RightColumnSpan = 12; + } else { + $LeftColumnSpan = 4; + $RightColumnSpan = 8; + } + if ($LeftColumnSpan > 0) { + echo "
    \n"; + + echo $this->callHook('leftContentPre'); + + if ($enableFolderTree) { + if ($showtree==1){ + $this->contentHeading("", true); + $this->contentContainerStart(); + /* + * access expandFolderTree with $this->params because it can + * be changed by preContent hook. + */ + $this->printNewTreeNavigationHtml($folderid, M_READ, 0, '', ($this->params['expandFolderTree'] == 1) ? -1 : 3, $orderby); + $this->contentContainerEnd(); + } else { + $this->contentHeading("", true); + } + } + + echo $this->callHook('leftContent'); + + if ($enableClipboard) $this->printClipboard($this->params['session']->getClipboard(), $previewer); + + echo $this->callHook('leftContentPost'); + + echo "
    \n"; + } + echo "
    \n"; + + if ($enableDropUpload && $folder->getAccessMode($user) >= M_READWRITE) { + echo "
    "; + echo "
    "; + } + +// $this->folderInfos(); +?> +
    getID()."\"" : "") ?>>
    +getAccessMode($user) >= M_READWRITE) { + echo "
    "; + echo "
    "; +// $this->dropUpload(); +?> +
    getID()."\"" : "") ?>>
    +"; + echo "
    "; + } + +// $this->folderList(); +?> +
    getID()."&orderby=".$orderby."\"" : "") ?>>
    +\n"; // End of right column div echo "
    \n"; // End of div around left and right column diff --git a/views/bootstrap/class.WorkflowGraph.php b/views/bootstrap/class.WorkflowGraph.php index 71f46f813..2eb3bcde2 100644 --- a/views/bootstrap/class.WorkflowGraph.php +++ b/views/bootstrap/class.WorkflowGraph.php @@ -185,8 +185,8 @@ cy.on('free', 'node', function(evt) { }); cy.on('tap', 'node', function(evt) { - var node = evt.cyTarget; - var scratch = node.scratch('app'); + var node = evt.target; + var scratch = node.scratch('_app'); if(typeof scratch !== 'undefined') { noty({ text: (scratch.users ? '

    ' ?> ' + scratch.users + '

    ' : '') + (scratch.groups ? ' ' ?> ' + scratch.groups + '

    ' : ''), @@ -272,7 +272,7 @@ $(document).ready(function() { position: {x: ".$positions[$nodeid]->x.", y: ".$positions[$nodeid]->y."}," : "")." classes: 'action".($iscurtransition ? " current" : ($this->curtransitions ? " light" : ""))."'".(!$this->curtransitions || $iscurtransition && $this->curtransitions ? ", scratch: { - app: {groups: \"".str_replace('"', "\\\"", implode(", ", $gnames))."\", users: \"".str_replace('"', "\\\"", implode(", ", $unames))."\"} + _app: {groups: \"".str_replace('"', "\\\"", implode(", ", $gnames))."\", users: \"".str_replace('"', "\\\"", implode(", ", $unames))."\"} }" : "")." });\n"; } @@ -321,6 +321,7 @@ $(document).ready(function() { echo "cy.add({ data: { id: 'E1-".$transition->getID()."', + name: '', source: 'S".$state->getID()."', target: 'A".$transition->getID()."-".$action->getID()."' }, @@ -329,6 +330,7 @@ $(document).ready(function() { echo "cy.add({ data: { id: 'E2-".$transition->getID()."', + name: '', source: 'A".$transition->getID()."-".$action->getID()."', target: 'S".$nextstate->getID()."' }, diff --git a/views/bootstrap/class.WorkflowSummary.php b/views/bootstrap/class.WorkflowSummary.php index d6e9503d1..64438cda9 100644 --- a/views/bootstrap/class.WorkflowSummary.php +++ b/views/bootstrap/class.WorkflowSummary.php @@ -36,6 +36,14 @@ require_once("SeedDMS/Preview.php"); */ class SeedDMS_View_WorkflowSummary extends SeedDMS_Bootstrap_Style { + function js() { /* {{{ */ + header('Content-Type: application/javascript; charset=UTF-8'); + parent::jsTranslations(array('cancel', 'splash_move_document', 'confirm_move_document', 'move_document', 'confirm_transfer_link_document', 'transfer_content', 'link_document', 'splash_move_folder', 'confirm_move_folder', 'move_folder')); + + $this->printDeleteDocumentButtonJs(); + $this->printClickDocumentJs(); + } /* }}} */ + function show() { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; diff --git a/webdav/index.php b/webdav/index.php index 8d1cf3e92..7c3bac0ed 100644 --- a/webdav/index.php +++ b/webdav/index.php @@ -1,5 +1,7 @@ _logFileEnable) { if ($settings->_logFileRotation=="h") $logname=date("YmdH", time()); else if ($settings->_logFileRotation=="d") $logname=date("Ymd", time()); @@ -17,16 +20,38 @@ if($settings->_logFileEnable) { @mkdir($settings->_contentDir.'log'); if(file_exists($settings->_contentDir.'log') && is_dir($settings->_contentDir.'log')) { $log = Log::factory('file', $logname); - $log->setMask(Log::MAX(PEAR_LOG_INFO)); + $log->setMask(Log::MAX(PEAR_LOG_DEBUG)); } else $log = null; } else { $log = null; } +$notifier = new SeedDMS_NotificationService(); + +if(isset($GLOBALS['SEEDDMS_HOOKS']['notification'])) { + foreach($GLOBALS['SEEDDMS_HOOKS']['notification'] as $notificationObj) { + if(method_exists($notificationObj, 'preAddService')) { + $notificationObj->preAddService($dms, $notifier); + } + } +} + +if($settings->_enableEmail) { + $notifier->addService(new SeedDMS_EmailNotify($dms, $settings->_smtpSendFrom, $settings->_smtpServer, $settings->_smtpPort, $settings->_smtpUser, $settings->_smtpPassword)); +} + +if(isset($GLOBALS['SEEDDMS_HOOKS']['notification'])) { + foreach($GLOBALS['SEEDDMS_HOOKS']['notification'] as $notificationObj) { + if(method_exists($notificationObj, 'postAddService')) { + $notificationObj->postAddService($dms, $notifier); + } + } +} + include("webdav.php"); $server = new HTTP_WebDAV_Server_SeedDMS(); -$server->ServeRequest($dms, $log); +$server->ServeRequest($dms, $log, $notifier); //$files = array(); //$options = array('path'=>'/Test1/subdir', 'depth'=>1); //echo $server->MKCOL(&$options); diff --git a/webdav/webdav.php b/webdav/webdav.php index 12dab5244..00c4e0d4f 100644 --- a/webdav/webdav.php +++ b/webdav/webdav.php @@ -31,6 +31,16 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server */ var $logger = null; + /** + * A reference to a notifier + * + * This is set by ServeRequest + * + * @access private + * @var object + */ + var $notifier = null; + /** * Currently logged in user * @@ -53,7 +63,7 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server * @access public * @param object $dms reference to DMS */ - function ServeRequest($dms = null, $logger = null) /* {{{ */ + function ServeRequest($dms = null, $logger = null, $notifier = null) /* {{{ */ { // set root directory, defaults to webserver document root if not set if ($dms) { @@ -65,6 +75,9 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server // set logger $this->logger = $logger; + // set notifier + $this->notifier = $notifier; + // special treatment for litmus compliance test // reply on its identifier header // not needed for the test itself but eases debugging @@ -93,6 +106,7 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server if($this->logger) { switch($methode) { case 'MOVE': + case 'COPY': $msg = $methode.': '.$options['path'].' -> '.$options['dest']; break; default: @@ -601,7 +615,7 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $document = $this->dms->getDocumentByName($name, $folder); if($document) { if($this->logger) - $this->logger->log('PUT: replacing document id='.$document->getID(), PEAR_LOG_INFO); + $this->logger->log('PUT: saving document id='.$document->getID(), PEAR_LOG_INFO); if ($document->getAccessMode($this->user, 'updateDocument') < M_READWRITE) { if($this->logger) $this->logger->log('PUT: no access on document', PEAR_LOG_ERR); @@ -633,13 +647,63 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server } else { if($this->logger) $this->logger->log('PUT: adding new version', PEAR_LOG_INFO); - if(!$document->addContent('', $this->user, $tmpFile, $name, $fileType, $mimetype, array(), array(), 0)) { + + if($settings->_enableFullSearch) { + $index = $indexconf['Indexer']::open($settings->_luceneDir); + $indexconf['Indexer']::init($settings->_stopWordsFile); + } else { + $index = null; + $indexconf = null; + } + + $controller = Controller::factory('UpdateDocument'); + $controller->setParam('dms', $this->dms); + $controller->setParam('user', $this->user); + $controller->setParam('documentsource', 'webdav'); + $controller->setParam('folder', $document->getFolder()); + $controller->setParam('document', $document); + $controller->setParam('index', $index); + $controller->setParam('indexconf', $indexconf); + $controller->setParam('comment', ''); + $controller->setParam('userfiletmp', $tmpFile); + $controller->setParam('userfilename', $name); + $controller->setParam('filetype', $fileType); + $controller->setParam('userfiletype', $mimetype); + $controller->setParam('reviewers', array()); + $controller->setParam('approvers', array()); + $controller->setParam('attributes', array()); + $controller->setParam('workflow', null); + + if(!$content = $controller->run()) { +// if(!$document->addContent('', $this->user, $tmpFile, $name, $fileType, $mimetype, array(), array(), 0)) { if($this->logger) $this->logger->log('PUT: error adding new version', PEAR_LOG_ERR); unlink($tmpFile); return "409 Conflict"; } } + if($this->notifier) { + if($this->logger) + $this->logger->log('PUT: Sending Notifications', PEAR_LOG_INFO); + $notifyList = $document->getNotifyList(); + $folder = $document->getFolder(); + + $subject = "document_updated_email_subject"; + $message = "document_updated_email_body"; + $params = array(); + $params['name'] = $document->getName(); + $params['folder_path'] = $folder->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['comment'] = $document->getComment(); + $params['version_comment'] = $content->getComment(); + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewDocument.php?documentid=".$document->getID(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $this->notifier->toList($this->user, $notifyList["users"], $subject, $message, $params); + foreach ($notifyList["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } } } } else { @@ -651,6 +715,16 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server unlink($tmpFile); return "403 Forbidden"; } + + /* Check if name already exists in the folder */ + /* + if(!$settings->_enableDuplicateDocNames) { + if($folder->hasDocumentByName($name)) { + return "403 Forbidden"; + } + } + */ + if($settings->_enableFullSearch) { $index = $indexconf['Indexer']::open($settings->_luceneDir); $indexconf['Indexer']::init($settings->_stopWordsFile); @@ -699,6 +773,33 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $this->logger->log('PUT: error adding object: '.$controller->getErrorMsg(), PEAR_LOG_ERR); return "409 Conflict ".$controller->getErrorMsg(); } + if($this->notifier) { + if($this->logger) + $this->logger->log('PUT: Sending Notifications', PEAR_LOG_INFO); + $fnl = $folder->getNotifyList(); + $dnl = $document->getNotifyList(); + $nl = array( + 'users'=>array_unique(array_merge($dnl['users'], $fnl['users']), SORT_REGULAR), + 'groups'=>array_unique(array_merge($dnl['groups'], $fnl['groups']), SORT_REGULAR) + ); + + $subject = "new_document_email_subject"; + $message = "new_document_email_body"; + $params = array(); + $params['name'] = $name; + $params['folder_name'] = $folder->getName(); + $params['folder_path'] = $folder->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['comment'] = ''; + $params['version_comment'] = ''; + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewFolder.php?folderid=".$folder->getID(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $this->notifier->toList($this->user, $nl["users"], $subject, $message, $params); + foreach ($nl["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } } unlink($tmpFile); @@ -713,7 +814,9 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server * @return bool true on success */ function MKCOL($options) /* {{{ */ - { + { + global $settings; + $this->log_options('MKCOL', $options); $path = $options["path"]; @@ -774,6 +877,33 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server return "409 Conflict ".$controller->getErrorMsg(); } + if($this->notifier) { + if($this->logger) + $this->logger->log('MKCOL: Sending Notifications', PEAR_LOG_INFO); + $fnl = $folder->getNotifyList(); + $snl = $subFolder->getNotifyList(); + $nl = array( + 'users'=>array_unique(array_merge($snl['users'], $fnl['users']), SORT_REGULAR), + 'groups'=>array_unique(array_merge($snl['groups'], $fnl['groups']), SORT_REGULAR) + ); + + $subject = "new_subfolder_email_subject"; + $message = "new_subfolder_email_body"; + $params = array(); + $params['name'] = $subFolder->getName(); + $params['folder_name'] = $folder->getName(); + $params['folder_path'] = $folder->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['comment'] = ''; + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewFolder.php?folderid=".$subFolder->getID(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $this->notifier->toList($this->user, $nl["users"], $subject, $message, $params); + foreach ($nl["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } + return ("201 Created"); } /* }}} */ @@ -820,6 +950,16 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $this->logger->log('DELETE: cannot delete, folder has children', PEAR_LOG_ERR); return "409 Conflict"; } + + $parent = $obj->getParent(); + $fnl = $obj->getNotifyList(); + $pnl = $parent->getNotifyList(); + $nl = array( + 'users'=>array_unique(array_merge($fnl['users'], $pnl['users']), SORT_REGULAR), + 'groups'=>array_unique(array_merge($fnl['groups'], $pnl['groups']), SORT_REGULAR) + ); + $foldername = $obj->getName(); + $controller = Controller::factory('RemoveFolder'); $controller->setParam('dms', $this->dms); $controller->setParam('user', $this->user); @@ -827,10 +967,39 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $controller->setParam('index', $index); $controller->setParam('indexconf', $indexconf); if(!$controller->run()) { -// if(!$obj->remove()) { return "409 Conflict ".$controller->getErrorMsg(); } + + if($this->notifier) { + if($this->logger) + $this->logger->log('DELETE: Sending Notifications', PEAR_LOG_INFO); + $subject = "folder_deleted_email_subject"; + $message = "folder_deleted_email_body"; + $params = array(); + $params['name'] = $foldername; + $params['folder_path'] = $parent->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewFolder.php?folderid=".$parent->getID(); + $this->notifier->toList($this->user, $nl["users"], $subject, $message, $params); + foreach ($nl["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } } else { + /* Get the notify list before removing the document + * Also inform the users/groups of the parent folder + */ + $folder = $obj->getFolder(); + $dnl = $obj->getNotifyList(); + $fnl = $folder->getNotifyList(); + $nl = array( + 'users'=>array_unique(array_merge($dnl['users'], $fnl['users']), SORT_REGULAR), + 'groups'=>array_unique(array_merge($dnl['groups'], $fnl['groups']), SORT_REGULAR) + ); + $docname = $obj->getName(); + $controller = Controller::factory('RemoveDocument'); $controller->setParam('dms', $this->dms); $controller->setParam('user', $this->user); @@ -838,9 +1007,26 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $controller->setParam('index', $index); $controller->setParam('indexconf', $indexconf); if(!$controller->run()) { -// if(!$obj->remove()) { return "409 Conflict ".$controller->getErrorMsg(); } + + if($this->notifier){ + if($this->logger) + $this->logger->log('DELETE: Sending Notifications', PEAR_LOG_INFO); + $subject = "document_deleted_email_subject"; + $message = "document_deleted_email_body"; + $params = array(); + $params['name'] = $docname; + $params['folder_path'] = $folder->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewFolder.php?folderid=".$folder->getID(); + $this->notifier->toList($this->user, $nl["users"], $subject, $message, $params); + foreach ($nl["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } } return "204 No Content"; @@ -855,6 +1041,8 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server */ function MOVE($options) /* {{{ */ { + global $settings; + $this->log_options('MOVE', $options); // no copying to different WebDAV Servers yet @@ -874,6 +1062,11 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $objdest = $this->reverseLookup($options["dest"]); $newdocname = ''; + /* if the destіnation could not be found, then a folder/document shall + * be renamed. In that case the source object is moved into the ѕame + * or different folder under a new name. + * $objdest will store the new destination folder afterwards + */ if(!$objdest) { /* check if at least the dest directory exists */ $dirname = dirname($options['dest']); @@ -908,13 +1101,13 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $fspath = $this->dms->contentDir.'/'.$content->getPath(); /* save the content as a new version in the destination document */ - if(!$objdest->addContent('', $this->user, $fspath, $content->getOriginalFileName(), $content->getFileType(), $content->getMimeType, array(), array(), 0)) { + if(!$objdest->addContent('', $this->user, $fspath, $content->getOriginalFileName(), $content->getFileType(), $content->getMimeType(), array(), array(), 0)) { unlink($tmpFile); return "409 Conflict"; } /* change the name of the destination object */ - $objdest->setName($objsource->getName()); + // $objdest->setName($objsource->getName()); /* delete the source object */ $objsource->remove(); @@ -922,11 +1115,94 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server return "204 No Content"; } elseif(get_class($objdest) == $this->dms->getClassname('folder')) { /* Set the new Folder of the source object */ - if(get_class($objsource) == $this->dms->getClassname('document')) - $objsource->setFolder($objdest); - elseif(get_class($objsource) == $this->dms->getClassname('folder')) - $objsource->setParent($objdest); - else + if(get_class($objsource) == $this->dms->getClassname('document')) { + /* Check if name already exists in the folder */ + if(!$settings->_enableDuplicateDocNames) { + if($newdocname) { + if($objdest->hasDocumentByName($newdocname)) { + return "403 Forbidden"; + } + } else { + if($objdest->hasDocumentByName($objsource->getName())) { + return "403 Forbidden"; + } + } + } + + $oldFolder = $objsource->getFolder(); + if($objsource->setFolder($objdest)) { + if($this->notifier) { + if($this->logger) + $this->logger->log('MOVE: Sending Notifications', PEAR_LOG_INFO); + $nl1 = $oldFolder->getNotifyList(); + $nl2 = $objsource->getNotifyList(); + $nl3 = $objdest->getNotifyList(); + $nl = array( + 'users'=>array_unique(array_merge($nl1['users'], $nl2['users'], $nl3['users']), SORT_REGULAR), + 'groups'=>array_unique(array_merge($nl1['groups'], $nl2['groups'], $nl3['groups']), SORT_REGULAR) + ); + $subject = "document_moved_email_subject"; + $message = "document_moved_email_body"; + $params = array(); + $params['name'] = $objsource->getName(); + $params['old_folder_path'] = $oldFolder->getFolderPathPlain(); + $params['new_folder_path'] = $objdest->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewDocument.php?documentid=".$objsource->getID(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $this->notifier->toList($this->user, $nl["users"], $subject, $message, $params); + foreach ($nl["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } + } else { + return "500 Internal server error"; + } + } elseif(get_class($objsource) == $this->dms->getClassname('folder')) { + /* Check if name already exists in the folder */ + if(!$settings->_enableDuplicateSubFolderNames) { + if($newdocname) { + if($objdest->hasSubFolderByName($newdocname)) { + return "403 Forbidden"; + } + } else { + if($objdest->hasSubFolderByName($objsource->getName())) { + return "403 Forbidden"; + } + } + } + $oldFolder = $objsource->getParent(); + if($objsource->setParent($objdest)) { + if($this->notifier) { + if($this->logger) + $this->logger->log('MOVE: Sending Notifications', PEAR_LOG_INFO); + $nl1 = $oldFolder->getNotifyList(); + $nl2 = $objsource->getNotifyList(); + $nl3 = $objdest->getNotifyList(); + $nl = array( + 'users'=>array_unique(array_merge($nl1['users'], $nl2['users'], $nl3['users']), SORT_REGULAR), + 'groups'=>array_unique(array_merge($nl1['groups'], $nl2['groups'], $nl3['groups']), SORT_REGULAR) + ); + $subject = "folder_moved_email_subject"; + $message = "folder_moved_email_body"; + $params = array(); + $params['name'] = $objsource->getName(); + $params['old_folder_path'] = $oldFolder->getFolderPathPlain(); + $params['new_folder_path'] = $objdest->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewFolder.php?folderid=".$objsource->getID(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $this->notifier->toList($this->user, $nl["users"], $subject, $message, $params); + foreach ($nl["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } + } else { + return "500 Internal server error"; + } + } else return "500 Internal server error"; if($newdocname) $objsource->setName($newdocname); @@ -940,12 +1216,11 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server * @param array general parameter passing array * @return bool true on success */ - function COPY($options, $del=false) /* {{{ */ + function COPY($options) /* {{{ */ { global $settings, $indexconf; - if(!$del) - $this->log_options('COPY', $options); + $this->log_options('COPY', $options); // TODO Property updates still broken (Litmus should detect this?) @@ -974,6 +1249,8 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server // get dest folder or document $objdest = $this->reverseLookup($options["dest"]); + // If the destination doesn't exists, then check if the parent folder exists + // and set $newdocname, which is later used to create a new document $newdocname = ''; if(!$objdest) { /* check if at least the dest directory exists */ @@ -995,7 +1272,7 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server return "403 Forbidden"; } - /* If destination object is a document it must be overwritten */ + /* If destination object is a document the source document will create a new version */ if(get_class($objdest) == $this->dms->getClassname('document')) { if (!$options["overwrite"]) { return "412 precondition failed"; @@ -1009,13 +1286,19 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $content = $objsource->getLatestContent(); $fspath = $this->dms->contentDir.'/'.$content->getPath(); + /* If the checksum of source and destination are equal, then do not copy */ + if($content->getChecksum() == $objdest->getLatestContent()->getChecksum()) { + return "204 No Content"; + } + /* save the content as a new version in the destination document */ - if(!$objdest->addContent('', $this->user, $fspath, $content->getOriginalFileName(), $content->getFileType(), $content->getMimeType, array(), array(), 0)) { + if(!$objdest->addContent('', $this->user, $fspath, $content->getOriginalFileName(), $content->getFileType(), $content->getMimeType(), array(), array(), 0)) { unlink($tmpFile); return "409 Conflict"; } - $objdest->setName($objsource->getName()); + /* Since 5.1.13 do not overwrite the name anymore + $objdest->setName($objsource->getName()); */ return "204 No Content"; } elseif(get_class($objdest) == $this->dms->getClassname('folder')) { @@ -1033,6 +1316,15 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server if(!$newdocname) $newdocname = $objsource->getName(); + /* Check if name already exists in the folder */ + /* + if(!$settings->_enableDuplicateDocNames) { + if($objdest->hasDocumentByName($newdocname)) { + return "403 Forbidden"; + } + } + */ + /* get the latest content of the source object */ $content = $objsource->getLatestContent(); $fspath = $this->dms->contentDir.'/'.$content->getPath(); @@ -1084,6 +1376,34 @@ class HTTP_WebDAV_Server_SeedDMS extends HTTP_WebDAV_Server $this->logger->log('COPY: error copying object', PEAR_LOG_ERR); return "409 Conflict"; } + + if($this->notifier) { + if($this->logger) + $this->logger->log('COPY: Sending Notifications', PEAR_LOG_INFO); + $fnl = $objdest->getNotifyList(); + $dnl = $document->getNotifyList(); + $nl = array( + 'users'=>array_unique(array_merge($dnl['users'], $fnl['users']), SORT_REGULAR), + 'groups'=>array_unique(array_merge($dnl['groups'], $fnl['groups']), SORT_REGULAR) + ); + + $subject = "new_document_email_subject"; + $message = "new_document_email_body"; + $params = array(); + $params['name'] = $name; + $params['folder_name'] = $objdest->getName(); + $params['folder_path'] = $objdest->getFolderPathPlain(); + $params['username'] = $this->user->getFullName(); + $params['comment'] = ''; + $params['version_comment'] = ''; + $params['url'] = "http".((isset($_SERVER['HTTPS']) && (strcmp($_SERVER['HTTPS'],'off')!=0)) ? "s" : "")."://".$_SERVER['HTTP_HOST'].$settings->_httpRoot."out/out.ViewFolder.php?folderid=".$objdest->getID(); + $params['sitename'] = $settings->_siteName; + $params['http_root'] = $settings->_httpRoot; + $this->notifier->toList($this->user, $nl["users"], $subject, $message, $params); + foreach ($nl["groups"] as $grp) { + $this->notifier->toGroup($this->user, $grp, $subject, $message, $params); + } + } return "201 Created"; } } /* }}} */
    ".getMLText("name")."".($parent ? '' : '')."".getMLText("name"); + print " ".($orderby=="n"||$orderby=="na"?' ':($orderby=="nd"?' ':' ')).""; + print " ".($orderby=="s"||$orderby=="sa"?' ':($orderby=="sd"?' ':' ')).""; + print " ".($orderby=="d"||$orderby=="da"?' ':($orderby=="dd"?' ':' ')).""; + print "".getMLText("owner")."".getMLText("status")."".getMLText("action")."