diff --git a/SeedDMS_Core/Core/inc.ClassAttribute.php b/SeedDMS_Core/Core/inc.ClassAttribute.php new file mode 100644 index 000000000..6731bf7d1 --- /dev/null +++ b/SeedDMS_Core/Core/inc.ClassAttribute.php @@ -0,0 +1,1352 @@ + + * @copyright Copyright (C) 2012 Uwe Steinmann + * @version Release: @package_version@ + */ + +/** + * Class to represent an attribute in the document management system + * + * Attributes are key/value pairs which can be attachted to documents, + * folders and document content. The number of attributes is unlimited. + * Each attribute has a value and is related to an attribute definition, + * which holds the name and other information about the attribute. + * + * @see SeedDMS_Core_AttributeDefinition + * + * @category DMS + * @package SeedDMS_Core + * @author Uwe Steinmann + * @copyright Copyright (C) 2012-2013 Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_Core_Attribute { /* {{{ */ + /** + * @var integer id of attribute + * + * @access protected + */ + protected $_id; + + /** + * @var object SeedDMS_Core_Object folder, document or document content + * this attribute belongs to + * + * @access protected + */ + protected $_obj; + + /** + * @var object SeedDMS_Core_AttributeDefinition definition of this attribute + * + * @access protected + */ + protected $_attrdef; + + /** + * @var mixed value of this attribute + * + * @access protected + */ + protected $_value; + + /** + * @var integer validation error + * + * @access protected + */ + protected $_validation_error; + + /** + * @var object SeedDMS_Core_DMS reference to the dms instance this attribute belongs to + * + * @access protected + */ + protected $_dms; + + /** + * Constructor + * + * @param integer $id internal id of attribute + * @param SeedDMS_Core_Object $obj object this attribute is attached to + * @param SeedDMS_Core_AttributeDefinition $attrdef reference to the attribute definition + * @param string $value value of the attribute + */ + function __construct($id, $obj, $attrdef, $value) { /* {{{ */ + $this->_id = $id; + $this->_obj = $obj; + $this->_attrdef = $attrdef; + $this->_value = $value; + $this->_validation_error = 0; + $this->_dms = null; + } /* }}} */ + + /** + * Set reference to dms + * + * @param SeedDMS_Core_DMS $dms + */ + function setDMS($dms) { /* {{{ */ + $this->_dms = $dms; + } /* }}} */ + + /** + * Get internal id of attribute + * + * @return integer id + */ + function getID() { return $this->_id; } + + /** + * Return attribute value as stored in database + * + * This function will return the value of multi value attributes + * including the separator char. + * + * @return string the attribute value as it is stored in the database. + */ + function getValue() { return $this->_value; } + + /** + * Return attribute values as an array + * + * This function returns the attribute value as an array. The array + * has one element for non multi value attributes and n elements for + * multi value attributes. + * + * @return array the attribute values + */ + function getValueAsArray() { /* {{{ */ + if($this->_attrdef->getMultipleValues()) { + /* If the value doesn't start with the separator used in the value set, + * then assume that the value was not saved with a leading separator. + * This can happen, if the value was previously a single value from + * the value set and later turned into a multi value attribute. + */ + $sep = substr($this->_value, 0, 1); + $vsep = $this->_attrdef->getValueSetSeparator(); + if($sep == $vsep) + return(explode($sep, substr($this->_value, 1))); + else + return(array($this->_value)); + } else { + return array($this->_value); + } + } /* }}} */ + + /** + * Set a value of an attribute + * + * The attribute is completely deleted if the value is an empty string + * or empty array. An array of values is only allowed if the attribute may + * have multiple values. If an array is passed and the attribute may + * have only a single value, then the first element of the array will + * be taken. + * + * @param string $values value as string or array to be set + * @return boolean true if operation was successfull, otherwise false + */ + function setValue($values) { /* {{{*/ + $db = $this->_dms->getDB(); + + if($this->_attrdef->getMultipleValues()) { + /* Multiple values without a value set is not allowed */ + if(!$valuesetstr = $this->_attrdef->getValueSet()) + return false; + $valueset = $this->_attrdef->getValueSetAsArray(); + + if(is_array($values)) { + if($values) { + $error = false; + foreach($values as $v) { + if(!in_array($v, $valueset)) { $error = true; break; } + } + if($error) + return false; + $valuesetstr = $this->_attrdef->getValueSet(); + $value = $valuesetstr[0].implode($valuesetstr[0], $values); + } else { + $value = ''; + } + } else { + if($values) { + if($valuesetstr[0] != $values[0]) + $values = explode($valuesetstr[0], $values); + else + $values = explode($valuesetstr[0], substr($values, 1)); + + $error = false; + foreach($values as $v) { + if(!in_array($v, $valueset)) { $error = true; break; } + } + if($error) + return false; + $value = $valuesetstr[0].implode($valuesetstr[0], $values); + } else { + $value = $values; + } + } + } else { + if(is_array($values)) { + if($values) + $value = $values[0]; + else + $value = ''; + } else { + $value = $values; + } + } + + switch(get_class($this->_obj)) { + case $this->_dms->getClassname('document'): + if(trim($value) === '') + $queryStr = "DELETE FROM tblDocumentAttributes WHERE `document` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId(); + else + $queryStr = "UPDATE tblDocumentAttributes SET value = ".$db->qstr($value)." WHERE `document` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId(); + break; + case $this->_dms->getClassname('documentcontent'): + if(trim($value) === '') + $queryStr = "DELETE FROM tblDocumentContentAttributes WHERE `content` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId(); + else + $queryStr = "UPDATE tblDocumentContentAttributes SET value = ".$db->qstr($value)." WHERE `content` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId(); + break; + case $this->_dms->getClassname('folder'): + if(trim($value) === '') + $queryStr = "DELETE FROM tblFolderAttributes WHERE `folder` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId(); + else + $queryStr = "UPDATE tblFolderAttributes SET value = ".$db->qstr($value)." WHERE `folder` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId(); + break; + default: + return false; + } + if (!$db->getResult($queryStr)) + return false; + + $this->_value = $value; + + return true; + } /* }}} */ + + /** + * Validate attribute value + * + * This function checks if the attribute values fits the attribute + * definition. + * If the validation fails the validation error will be set which + * can be requested by SeedDMS_Core_Attribute::getValidationError() + * + * @return boolean true if validation succeds, otherwise false + */ + function validate() { /* {{{ */ + $attrdef = $this->_attrdef(); + $result = $attrdef->validate($this->_value); + $this->_validation_error = $attrdef->getValidationError(); + return $result; + } /* }}} */ + + /** + * Get validation error from last validation + * + * @return integer error code + */ + function getValidationError() { return $this->_validation_error; } + + /** + * Get definition of attribute + * + * @return object attribute definition + */ + function getAttributeDefinition() { return $this->_attrdef; } + +} /* }}} */ + +/** + * Class to represent an attribute definition in the document management system + * + * Attribute definitions specify the name, type, object type, minimum and + * maximum values and a value set. The object type determines the object + * an attribute may be attached to. If the object type is set to object_all + * the attribute can be used for documents, document content and folders. + * + * The type of an attribute specifies the skalar data type. + * + * Attributes for which multiple values are allowed must have the + * multiple flag set to true and specify a value set. A value set + * is a string consisting of n separated values. The separator is the + * first char of the value set. A possible value could be '|REV-A|REV-B' + * If multiple values are allowed, then minvalues and maxvalues may + * restrict the allowed number of values. + * + * @see SeedDMS_Core_Attribute + * + * @category DMS + * @package SeedDMS_Core + * @author Markus Westphal, Malcolm Cowe, Uwe Steinmann + * @copyright Copyright (C) 2012 Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_Core_AttributeDefinition { /* {{{ */ + /** + * @var integer id of attribute definition + * + * @access protected + */ + protected $_id; + + /** + * @var string name of attribute definition + * + * @access protected + */ + protected $_name; + + /** + * @var string object type of attribute definition. This can be one of + * type_int, type_float, type_string, type_boolean, type_url, or type_email. + * + * @access protected + */ + protected $_type; + + /** + * @var string type of attribute definition. This can be one of objtype_all, + * objtype_folder, objtype_document, or objtype_documentcontent. + * + * @access protected + */ + protected $_objtype; + + /** + * @var boolean whether an attribute can have multiple values + * + * @access protected + */ + protected $_multiple; + + /** + * @var integer minimum values of an attribute + * + * @access protected + */ + protected $_minvalues; + + /** + * @var integer maximum values of an attribute + * + * @access protected + */ + protected $_maxvalues; + + /** + * @var string list of possible values of an attribute + * + * @access protected + */ + protected $_valueset; + + /** + * @var string regular expression the value must match + * + * @access protected + */ + protected $_regex; + + /** + * @var integer validation error + * + * @access protected + */ + protected $_validation_error; + + /** + * @var object SeedDMS_Core_DMS reference to the dms instance this attribute definition belongs to + * + * @access protected + */ + protected $_dms; + + /* + * Possible skalar data types of an attribute + */ + const type_int = '1'; + const type_float = '2'; + const type_string = '3'; + const type_boolean = '4'; + const type_url = '5'; + const type_email = '6'; + const type_date = '7'; + + /* + * The object type for which a attribute may be used + */ + const objtype_all = '0'; + const objtype_folder = '1'; + const objtype_document = '2'; + const objtype_documentcontent = '3'; + + /** + * Constructor + * + * @param integer $id internal id of attribute definition + * @param string $name name of attribute + * @param integer $objtype type of object for which this attribute definition + * may be used. + * @param integer $type skalar type of attribute + * @param boolean $multiple set to true if multiple values are allowed + * @param integer $minvalues minimum number of values + * @param integer $maxvalues maximum number of values + * @param string $valueset separated list of allowed values, the first char + * is taken as the separator + */ + function __construct($id, $name, $objtype, $type, $multiple, $minvalues, $maxvalues, $valueset, $regex) { /* {{{ */ + $this->_id = $id; + $this->_name = $name; + $this->_type = $type; + $this->_objtype = $objtype; + $this->_multiple = $multiple; + $this->_minvalues = $minvalues; + $this->_maxvalues = $maxvalues; + $this->_valueset = $valueset; + $this->_separator = ''; + $this->_regex = $regex; + $this->_dms = null; + $this->_validation_error = 0; + } /* }}} */ + + /** + * Set reference to dms + * + * @param SeedDMS_Core_DMS $dms + */ + function setDMS($dms) { /* {{{ */ + $this->_dms = $dms; + } /* }}} */ + + /** + * Get internal id of attribute definition + * + * @return integer id + */ + function getID() { return $this->_id; } + + /** + * Get name of attribute definition + * + * @return string name + */ + function getName() { return $this->_name; } + + function setName($name) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET name =".$db->qstr($name)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_name = $name; + return true; + } /* }}} */ + + /** + * Get object type of attribute definition + * + * This can be one of objtype_all, + * objtype_folder, objtype_document, or objtype_documentcontent. + * + * @return integer type + */ + function getObjType() { return $this->_objtype; } + + /** + * Set object type of attribute definition + * + * This can be one of objtype_all, + * objtype_folder, objtype_document, or objtype_documentcontent. + * + * @param integer $objtype type + */ + function setObjType($objtype) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET objtype =".intval($objtype)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_objtype = $objtype; + return true; + } /* }}} */ + + /** + * Get type of attribute definition + * + * This can be one of type_int, type_float, type_string, type_boolean, + * type_url, type_email. + * + * @return integer type + */ + function getType() { return $this->_type; } + + /** + * Set type of attribute definition + * + * This can be one of type_int, type_float, type_string, type_boolean, + * type_url, type_email. + * + * @param integer $type type + */ + function setType($type) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET type =".intval($type)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_type = $type; + return true; + } /* }}} */ + + /** + * Check if attribute definition allows multi values for attribute + * + * @return boolean true if attribute may have multiple values + */ + function getMultipleValues() { return $this->_multiple; } + + /** + * Set if attribute definition allows multi values for attribute + * + * @param boolean $mv true if attribute may have multiple values, otherwise + * false + */ + function setMultipleValues($mv) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET multiple =".intval($mv)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_multiple = $mv; + return true; + } /* }}} */ + + /** + * Return minimum number of values for attributes + * + * Attributes with multiple values may be limited to a range + * of values. This functions returns the minimum number of values. + * + * @return integer minimum number of values + */ + function getMinValues() { return $this->_minvalues; } + + function setMinValues($minvalues) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET minvalues =".intval($minvalues)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_minvalues = $minvalues; + return true; + } /* }}} */ + + /** + * Return maximum number of values for attributes + * + * Attributes with multiple values may be limited to a range + * of values. This functions returns the maximum number of values. + * + * @return integer maximum number of values + */ + function getMaxValues() { return $this->_maxvalues; } + + function setMaxValues($maxvalues) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET maxvalues =".intval($maxvalues)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_maxvalues = $maxvalues; + return true; + } /* }}} */ + + /** + * Get the value set as saved in the database + * + * This is a string containing the list of valueѕ separated by a + * delimiter which also precedes the whole string, e.g. '|Yes|No' + * + * Use {@link SeedDMS_Core_AttributeDefinition::getValueSetAsArray()} + * for a list of values returned as an array. + * + * @return string value set + */ + function getValueSet() { /* {{{ */ + return $this->_valueset; + } /* }}} */ + + /** + * Get the separator used for the value set + * + * This is the first char of the value set string. + * + * @return string separator or an empty string if a value set is not set + */ + function getValueSetSeparator() { /* {{{ */ + if(strlen($this->_valueset) > 1) + return $this->_valueset[0]; + else + return ''; + } /* }}} */ + + /** + * Get the whole value set as an array + * + * @return array values of value set or false if the value set has + * less than 2 chars + */ + function getValueSetAsArray() { /* {{{ */ + if(strlen($this->_valueset) > 1) + return array_map('trim', explode($this->_valueset[0], substr($this->_valueset, 1))); + else + return array(); + } /* }}} */ + + /** + * Get the n'th value of a value set + * + * @param interger $index + * @return string n'th value of value set or false if the index is + * out of range or the value set has less than 2 chars + */ + function getValueSetValue($ind) { /* {{{ */ + if(strlen($this->_valueset) > 1) { + $tmp = explode($this->_valueset[0], substr($this->_valueset, 1)); + if(isset($tmp[$ind])) + return trim($tmp[$ind]); + else + return false; + } else + return false; + } /* }}} */ + + /** + * Set the value set + * + * A value set is a list of values allowed for an attribute. The values + * are separated by a char which must also be the first char of the + * value set string. + * + * @param string $valueset + * @return boolean true if value set could be set, otherwise false + */ + function setValueSet($valueset) { /* {{{ */ + /* + $tmp = array(); + foreach($valueset as $value) { + $tmp[] = str_replace('"', '""', $value); + } + $valuesetstr = implode(",", $tmp); + */ + if(trim($valueset)) { + $valuesetarr = array_map('trim', explode($valueset[0], substr($valueset, 1))); + $valuesetstr = $valueset[0].implode($valueset[0], $valuesetarr); + } else { + $valuesetstr = ''; + } + + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET valueset =".$db->qstr($valuesetstr)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_valueset = $valueset; + $this->_separator = substr($valueset, 0, 1); + return true; + } /* }}} */ + + /** + * Get the regular expression as saved in the database + * + * @return string regular expression + */ + function getRegex() { /* {{{ */ + return $this->_regex; + } /* }}} */ + + /** + * Set the regular expression + * + * A value of the attribute must match this regular expression. + * + * @param string $regex + * @return boolean true if regex could be set, otherwise false + */ + function setRegex($regex) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitions SET regex =".$db->qstr($regex)." WHERE id = " . $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_regex = $regex; + return true; + } /* }}} */ + + /** + * Check if the attribute definition is used + * + * Checks all documents, folders and document content whether at least + * one of them referenceѕ this attribute definition + * + * @return boolean true if attribute definition is used, otherwise false + */ + function isUsed() { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "SELECT * FROM tblDocumentAttributes WHERE attrdef=".$this->_id; + $resArr = $db->getResultArray($queryStr); + if (is_array($resArr) && count($resArr) == 0) { + $queryStr = "SELECT * FROM tblFolderAttributes WHERE attrdef=".$this->_id; + $resArr = $db->getResultArray($queryStr); + if (is_array($resArr) && count($resArr) == 0) { + $queryStr = "SELECT * FROM tblDocumentContentAttributes WHERE attrdef=".$this->_id; + $resArr = $db->getResultArray($queryStr); + if (is_array($resArr) && count($resArr) == 0) { + + return false; + } + } + } + return true; + } /* }}} */ + + /** + * Parse a given value according to attribute definition + * + * The return value is always an array, even if the attribute is single + * value attribute. + * + * @return array list of single values + */ + function parseValue($value) { /* {{{ */ + $db = $this->_dms->getDB(); + + if($this->getMultipleValues()) { + /* If the value doesn't start with the separator used in the value set, + * then assume that the value was not saved with a leading separator. + * This can happen, if the value was previously a single value from + * the value set and later turned into a multi value attribute. + */ + $sep = substr($value, 0, 1); + $vsep = $this->getValueSetSeparator(); + if($sep == $vsep) + return(explode($sep, substr($value, 1))); + else + return(array($value)); + } else { + return array($value); + } + return true; + } /* }}} */ + + /** + * Return a list of documents, folders, document contents where this + * attribute definition is used + * + * @param integer $limit return not more the n objects of each type + * @return boolean true if attribute definition is used, otherwise false + */ + function getStatistics($limit=0) { /* {{{ */ + $db = $this->_dms->getDB(); + + $result = array('docs'=>array(), 'folders'=>array(), 'contents'=>array()); + if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all || + $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_document) { + $queryStr = "SELECT * FROM tblDocumentAttributes WHERE attrdef=".$this->_id; + if($limit) + $queryStr .= " limit ".(int) $limit; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + foreach($resArr as $rec) { + if($doc = $this->_dms->getDocument($rec['document'])) { + $result['docs'][] = $doc; + } + } + } + $queryStr = "SELECT count(*) c, value FROM tblDocumentAttributes WHERE attrdef=".$this->_id." GROUP BY value ORDER BY c DESC"; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + $result['frequencies']['document'] = $resArr; + } + } + + if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all || + $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_folder) { + $queryStr = "SELECT * FROM tblFolderAttributes WHERE attrdef=".$this->_id; + if($limit) + $queryStr .= " limit ".(int) $limit; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + foreach($resArr as $rec) { + if($folder = $this->_dms->getFolder($rec['folder'])) { + $result['folders'][] = $folder; + } + } + } + $queryStr = "SELECT count(*) c, value FROM tblFolderAttributes WHERE attrdef=".$this->_id." GROUP BY value ORDER BY c DESC"; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + $result['frequencies']['folder'] = $resArr; + } + } + + if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all || + $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_documentcontent) { + $queryStr = "SELECT * FROM tblDocumentContentAttributes WHERE attrdef=".$this->_id; + if($limit) + $queryStr .= " limit ".(int) $limit; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + foreach($resArr as $rec) { + if($content = $this->_dms->getDocumentContent($rec['content'])) { + $result['contents'][] = $content; + } + } + } + $queryStr = "SELECT count(*) c, value FROM tblDocumentContentAttributes WHERE attrdef=".$this->_id." GROUP BY value ORDER BY c DESC"; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + $result['frequencies']['content'] = $resArr; + } + } + + return $result; + } /* }}} */ + + /** + * Remove the attribute definition + * Removal is only executed when the definition is not used anymore. + * + * @return boolean true on success or false in case of an error + */ + function remove() { /* {{{ */ + $db = $this->_dms->getDB(); + + if($this->isUsed()) + return false; + + // Delete attribute definition group itself + $queryStr = "DELETE FROM tblAttributeDefinitionGroups WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) return false; + + return true; + } /* }}} */ + + /** + * Get all documents and folder by a given attribute value + * + * @param string $attrvalue value of attribute + * @param integer $limit limit number of documents/folders + * @return array array containing list of documents and folders + */ + public function getObjects($attrvalue, $limit) { /* {{{ */ + $db = $this->_dms->getDB(); + + $result = array('docs'=>array(), 'folders'=>array(), 'contents'=>array()); + if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all || + $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_document) { + $queryStr = "SELECT * FROM tblDocumentAttributes WHERE attrdef=".$this->_id." AND value=".$db->qstr($attrvalue); + if($limit) + $queryStr .= " limit ".(int) $limit; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + foreach($resArr as $rec) { + if($doc = $this->_dms->getDocument($rec['document'])) { + $result['docs'][] = $doc; + } + } + } + } + + if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all || + $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_folder) { + $queryStr = "SELECT * FROM tblFolderAttributes WHERE attrdef=".$this->_id." AND value=".$db->qstr($attrvalue); + if($limit) + $queryStr .= " limit ".(int) $limit; + $resArr = $db->getResultArray($queryStr); + if($resArr) { + foreach($resArr as $rec) { + if($folder = $this->_dms->getFolder($rec['folder'])) { + $result['folders'][] = $folder; + } + } + } + } + + return $result; + } /* }}} */ + + /** + * Validate value against attribute definition + * + * This function checks if the given value fits the attribute + * definition. + * If the validation fails the validation error will be set which + * can be requested by SeedDMS_Core_Attribute::getValidationError() + * + * @param string|array $attrvalue attribute value + * @return boolean true if validation succeds, otherwise false + */ + function validate($attrvalue) { /* {{{ */ + if($this->getMultipleValues()) { + if(is_string($attrvalue)) { + $sep = $attrvalue[0]; + $vsep = $this->getValueSetSeparator(); + if($sep == $vsep) + $values = explode($attrvalue[0], substr($attrvalue, 1)); + else + $values = array($attrvalue); + } else + $values = $attrvalue; + } elseif($attrvalue) { + $values = array($attrvalue); + } else { + $values = array(); + } + + $this->_validation_error = 0; + if($this->getMinValues() > count($values)) { + $this->_validation_error = 1; + return false; + } + if($this->getMaxValues() && $this->getMaxValues() < count($values)) { + $this->_validation_error = 2; + return false; + } + + $success = true; + switch((string) $this->getType()) { + case self::type_boolean: + foreach($values as $value) { + $success &= preg_match('/^[01]$/', $value) ? true : false; + } + if(!$success) + $this->_validation_error = 8; + break; + case self::type_int: + foreach($values as $value) { + $success &= preg_match('/^[0-9]*$/', $value) ? true : false; + } + if(!$success) + $this->_validation_error = 6; + break; + case self::type_date: + foreach($values as $value) { + $success &= preg_match('/^[12][0-9]{3}-[01][0-9]-[0-9]{2}$/', $value) ? true : false; + } + if(!$success) + $this->_validation_error = 9; + break; + case self::type_float: + foreach($values as $value) { + $success &= is_numeric($value); + } + if(!$success) + $this->_validation_error = 7; + break; + case self::type_string: + if(trim($this->getRegex()) != '') { + foreach($values as $value) { + $success &= preg_match($this->getRegex(), $value) ? true : false; + } + } + if(!$success) + $this->_validation_error = 3; + break; + case self::type_boolean: + foreach($values as $value) { + $success &= preg_match('/^[01]$/', $value); + } + break; + case self::type_email: + foreach($values as $value) { + $success &= preg_match('/^[a-z0-9._-]+@+[a-z0-9._-]+\.+[a-z]{2,4}$/i', $value); + } + if(!$success) + $this->_validation_error = 5; + break; + case self::type_url: + foreach($values as $value) { + $success &= preg_match('/^http(s)?:\/\/[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(\/.*)?$/i', $value); + } + if(!$success) + $this->_validation_error = 4; + break; + } + + if(!$success) + return $success; + + /* Check if value is in value set */ + if($valueset = $this->getValueSetAsArray()) { + foreach($values as $value) { + if(!in_array($value, $valueset)) { + $success = false; + $this->_validation_error = 10; + } + } + } + + return $success; + + } /* }}} */ + + /** + * Get validation error from last validation + * + * @return integer error code + */ + function getValidationError() { return $this->_validation_error; } + +} /* }}} */ + +/** + * Class to represent an attribute defintion group in the document management system + * + * @category DMS + * @package SeedDMS_Core + * @author Uwe Steinmann + * @copyright Copyright (C) 2016 Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_Core_AttributeDefinitionGroup { /* {{{ */ + /** + * The id of the attribute definition group + * + * @var integer + */ + protected $_id; + + /** + * The name of the attribute definition group + * + * @var string + */ + protected $_name; + + /** + * The comment of the attribute definition group + * + * @var string + */ + protected $_comment; + + /** + * Back reference to DMS this attribute definition group belongs to + * + * @var object + */ + protected $_dms; + + /* + * When an attribute in a attribute definition group is shown + */ + const show_never = 0x0; + const show_list = 0x1; + const show_details = 0x2; + const show_search = 0x4; + + function __construct($id, $name, $comment) { /* {{{ */ + $this->_id = $id; + $this->_name = $name; + $this->_comment = $comment; + $this->_dms = null; + } /* }}} */ + + /** + * Create an instance of a group object + * + * @param string|integer $id Id, name of group, depending + * on the 3rd parameter. + * @param object $dms instance of dms + * @param string $by search by group name if set to 'name'. + * Search by Id of group if left empty. + * @return object instance of class SeedDMS_Core_Group + */ + public static function getInstance($id, $dms, $by='') { /* {{{ */ + $db = $dms->getDB(); + + switch($by) { + case 'name': + $queryStr = "SELECT * FROM `tblAttributeDefinitionGroups` WHERE `name` = ".$db->qstr($id); + break; + default: + $queryStr = "SELECT * FROM `tblAttributeDefinitionGroups` WHERE id = " . (int) $id; + } + + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + else if (count($resArr) != 1) //wenn, dann wohl eher 0 als > 1 ;-) + return false; + + $resArr = $resArr[0]; + + $group = new self($resArr["id"], $resArr["name"], $resArr["comment"]); + $group->setDMS($dms); + return $group; + } /* }}} */ + + public static function getAllInstances($orderby, $dms) { /* {{{ */ + $db = $dms->getDB(); + + switch($orderby) { + default: + $queryStr = "SELECT * FROM tblAttributeDefinitionGroups ORDER BY name"; + } + $resArr = $db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + $groups = array(); + for ($i = 0; $i < count($resArr); $i++) { + $group = new self($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["comment"]); + $group->setDMS($dms); + $groups[$i] = $group; + } + + return $groups; + } /* }}} */ + + function setDMS($dms) { /* {{{ */ + $this->_dms = $dms; + } /* }}} */ + + function getID() { return $this->_id; } + + function getName() { return $this->_name; } + + function setName($newName) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitionGroups SET name = ".$db->qstr($newName)." WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_name = $newName; + return true; + } /* }}} */ + + function getComment() { return $this->_comment; } + + function setComment($newComment) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitionGroups SET comment = ".$db->qstr($newComment)." WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_comment = $newComment; + return true; + } /* }}} */ + + function getSequence($attrdef) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "SELECT * FROM `tblAttributeDefinitionGroupAttributeDefinition` ". + "WHERE `attrgrp` = '". $this->_id ."' AND `attrdef` = ".$attrdef->getID(); + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + return false; + + return (float) $resArr[0]['sequence']; + } /* }}} */ + + function setSequence($attrdef, $newSequence) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitionGroupAttributeDefinition SET `sequence` = ".$db->qstr($newSequence)." WHERE `attrgrp` = " . $this->_id . " AND `attrdef` = " . $attrdef->getID(); + if (!$db->getResult($queryStr)) + return false; + + return true; + } /* }}} */ + + function getShow($attrdef) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "SELECT * FROM `tblAttributeDefinitionGroupAttributeDefinition` ". + "WHERE `attrgrp` = '". $this->_id ."' AND `attrdef` = ".$attrdef->getID(); + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + return false; + + return (float) $resArr[0]['show']; + } /* }}} */ + + function setShow($attrdef, $newShow) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblAttributeDefinitionGroupAttributeDefinition SET `show` = ".$db->qstr($newShow)." WHERE `attrgrp` = " . $this->_id . " AND `attrdef` = " . $attrdef->getID(); + if (!$db->getResult($queryStr)) + return false; + + return true; + } /* }}} */ + + function getAttributeDefinitions($objtype=array()) { /* {{{ */ + $db = $this->_dms->getDB(); + + if (!isset($this->_attrdefs)) { + $queryStr = "SELECT `tblAttributeDefinitions`.* FROM `tblAttributeDefinitions` ". + "LEFT JOIN `tblAttributeDefinitionGroupAttributeDefinition` ON `tblAttributeDefinitionGroupAttributeDefinition`.`attrdef`=`tblAttributeDefinitions`.`id` ". + "WHERE `tblAttributeDefinitionGroupAttributeDefinition`.`attrgrp` = '". $this->_id ."' "; + if($objtype) { + if(is_array($objtype)) + $queryStr .= ' AND `tblAttributeDefinitions`.`objtype` in (\''.implode("','", $objtype).'\') '; + else + $queryStr .= ' AND `tblAttributeDefinitions`.`objtype`='.intval($objtype).' '; + } + $queryStr .= "ORDER BY `tblAttributeDefinitionGroupAttributeDefinition`.`sequence` ASC"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + $this->_attrdefs = array(); + + foreach ($resArr as $row) { + $attrdef = new SeedDMS_Core_AttributeDefinition($row["id"], $row["name"], $row["objtype"], $row["type"], $row["multiple"], $row["minvalues"], $row["maxvalues"], $row["valueset"], $row["regex"]); + $attrdef->setDMS($this->_dms); + array_push($this->_attrdefs, $attrdef); + } + } + return $this->_attrdefs; + } /* }}} */ + + function addAttributeDefinition($attrdef, $show=false) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "SELECT MAX(`sequence`) as m FROM `tblAttributeDefinitionGroupAttributeDefinition` ". + "WHERE `attrgrp` = '". $this->_id."'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + $seq = 10.0; + else + $seq = $resArr[0]['m'] + 10.0; + + $queryStr = "INSERT INTO tblAttributeDefinitionGroupAttributeDefinition (`attrgrp`, `attrdef`, `sequence`, `show`) VALUES (".$this->_id.", ".$attrdef->getID(). ", " . $seq . ", " . (int) $show ." )"; + $res = $db->getResult($queryStr); + + if (!$res) return false; + + unset($this->_attrdefs); + return true; + } /* }}} */ + + function removeAttributeDefinition($attrdef) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "DELETE FROM tblAttributeDefinitionGroupAttributeDefinition WHERE attrgrp = ".$this->_id." AND attrdef = ".$attrdef->getID(); + $res = $db->getResult($queryStr); + + if (!$res) return false; + unset($this->_attrdefs); + return true; + } /* }}} */ + + /** + * Check if attribute definition is member of group + * + * @param object $attrdef attribute definition to check + * @return boolean true if attribute definition is a member otherwise false + */ + function isMember($attrdef) { /* {{{ */ + $db = $this->_dms->getDB(); + $queryStr = "SELECT * FROM tblAttributeDefinitionGroupAttributeDefinition WHERE attrgrp = " . $this->_id . " AND attrdef = " . $attrdef->getID(); + + $resArr = $db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) return false; + if (count($resArr) != 1) return false; + + return true; + } /* }}} */ + + /** + * Get all folders this attribute definition is assigned to + * + * @return array list of folders + */ + function getFolders() { /* {{{ */ + $db = $this->_dms->getDB(); + + if (!isset($this->_folders)) + { + $queryStr = "SELECT `tblFolderAttributeDefinitionGroup`.* FROM `tblFolderAttributeDefinitionGroup` WHERE `tblFolderAttributeDefinitionGroup`.`attrgrp`='". $this->_id ."'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + $this->_folders = array(); + foreach ($resArr as $row) { + $folder = $this->_dms->getFolder($row["folder"]); + $folder->setDMS($this->_dms); + array_push($this->_folders, $folder); + } + } + return $this->_folders; + } /* }}} */ + + /** + * Delete attribute definition group + * This function deletes the attribute definition group and all it + * references. + * + * @return boolean true on success or false in case of an error + */ + function remove() { /* {{{ */ + $db = $this->_dms->getDB(); + + $db->startTransaction(); + + $queryStr = "DELETE FROM tblAttributeDefinitionGroups WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + + $db->commitTransaction(); + + return true; + } /* }}} */ + +} /* }}} */ +?> diff --git a/SeedDMS_Core/Core/inc.ClassDMS.php b/SeedDMS_Core/Core/inc.ClassDMS.php new file mode 100644 index 000000000..0d176da5a --- /dev/null +++ b/SeedDMS_Core/Core/inc.ClassDMS.php @@ -0,0 +1,2951 @@ + + * @copyright Copyright (C) 2010, Uwe Steinmann + * @version Release: @package_version@ + */ + +/** + * Include some files + */ +require_once("inc.AccessUtils.php"); +require_once("inc.FileUtils.php"); +require_once("inc.ClassAccess.php"); +require_once("inc.ClassObject.php"); +require_once("inc.ClassFolder.php"); +require_once("inc.ClassDocument.php"); +require_once("inc.ClassGroup.php"); +require_once("inc.ClassUser.php"); +require_once("inc.ClassKeywords.php"); +require_once("inc.ClassNotification.php"); +require_once("inc.ClassAttribute.php"); + +/** + * Class to represent the complete document management system. + * This class is needed to do most of the dms operations. It needs + * an instance of {@link SeedDMS_Core_DatabaseAccess} to access the + * underlying database. Many methods are factory functions which create + * objects representing the entities in the dms, like folders, documents, + * users, or groups. + * + * Each dms has its own database for meta data and a data store for document + * content. Both must be specified when creating a new instance of this class. + * All folders and documents are organized in a hierachy like + * a regular file system starting with a {@link $rootFolderID} + * + * This class does not enforce any access rights on documents and folders + * by design. It is up to the calling application to use the methods + * {@link SeedDMS_Core_Folder::getAccessMode()} and + * {@link SeedDMS_Core_Document::getAccessMode()} and interpret them as desired. + * Though, there are two convenient functions to filter a list of + * documents/folders for which users have access rights for. See + * {@link filterAccess()} + * and {@link filterUsersByAccess()} + * + * Though, this class has a method to set the currently logged in user + * ({@link setUser}), it does not have to be called, because + * there is currently no class within the SeedDMS core which needs the logged + * in user. {@link SeedDMS_Core_DMS} itself does not do any user authentication. + * It is up to the application using this class. + * + * + * connect() or die ("Could not connect to db-server"); + * $dms = new SeedDMS_Core_DMS($db, $contentDir); + * $dms->setRootFolderID(1); + * ... + * ?> + * + * + * @category DMS + * @package SeedDMS_Core + * @version @version@ + * @author Uwe Steinmann + * @copyright Copyright (C) 2010, Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_Core_DMS { + /** + * @var object $db reference to database object. This must be an instance + * of {@link SeedDMS_Core_DatabaseAccess}. + * @access protected + */ + protected $db; + + /** + * @var array $classnames list of classnames for objects being instanciate + * by the dms + * @access protected + */ + protected $classnames; + + /** + * @var object $user reference to currently logged in user. This must be + * an instance of {@link SeedDMS_Core_User}. This variable is currently not + * used. It is set by {@link setUser}. + * @access private + */ + private $user; + + /** + * @var string $contentDir location in the file system where all the + * document data is located. This should be an absolute path. + * @access public + */ + public $contentDir; + + /** + * @var integer $rootFolderID ID of root folder + * @access public + */ + public $rootFolderID; + + /** + * @var integer $maxDirID maximum number of documents per folder on the + * filesystem. If this variable is set to a value != 0, the content + * directory will have a two level hierarchy for document storage. + * @access public + */ + public $maxDirID; + + /** + * @var boolean $enableConverting set to true if conversion of content + * is desired + * @access public + */ + public $enableConverting; + + /** + * @var boolean $forceRename use renameFile() instead of copyFile() when + * copying the document content into the data store. The default is + * to copy the file. This parameter only affects the methods + * SeedDMS_Core_Document::addDocument() and + * SeedDMS_Core_Document::addDocumentFile(). Setting this to true + * may save resources especially for large files. + * @access public + */ + public $forceRename; + + /** + * @var array $convertFileTypes list of files types that shall be converted + * @access public + */ + public $convertFileTypes; + + /** + * @var array $viewOnlineFileTypes list of files types that can be viewed + * online + * @access public + */ + public $viewOnlineFileTypes; + + /** + * @var array $noReadForStatus list of status without read right + * online + * @access public + */ + public $noReadForStatus; + + /** + * @var string $version version of pear package + * @access public + */ + public $version; + + /** + * @var array $callbacks list of methods called when certain operations, + * like removing a document, are executed. Set a callback with + * {@link SeedDMS_Core_DMS::setCallback()}. + * The key of the array is the internal callback function name. Each + * array element is an array with two elements: the function name + * and the parameter passed to the function. + * + * Currently implemented callbacks are: + * + * onPreRemoveDocument($user_param, $document); + * called before deleting a document. If this function returns false + * the document will not be deleted. + * + * onPostRemoveDocument($user_param, $document_id); + * called after the successful deletion of a document. + * + * @access public + */ + public $callbacks; + + + /** + * Checks if two objects are equal by comparing their IDs + * + * The regular php check done by '==' compares all attributes of + * two objects, which is often not required. The method will first check + * if the objects are instances of the same class and than if they + * have the same id. + * + * @param object $object1 first object to be compared + * @param object $object2 second object to be compared + * @return boolean true if objects are equal, otherwise false + */ + static function checkIfEqual($object1, $object2) { /* {{{ */ + if(get_class($object1) != get_class($object2)) + return false; + if($object1->getID() != $object2->getID()) + return false; + return true; + } /* }}} */ + + /** + * Checks if a list of objects contains a single object by comparing their IDs + * + * This function is only applicable on list containing objects which have + * a method getID() because it is used to check if two objects are equal. + * The regular php check on objects done by '==' compares all attributes of + * two objects, which isn't required. The method will first check + * if the objects are instances of the same class. + * + * The result of the function can be 0 which happens if the first element + * of an indexed array matches. + * + * @param object $object1 object to look for (needle) + * @param array $list list of objects (haystack) + * @return boolean/integer index in array if object was found, otherwise false + */ + static function inList($object, $list) { /* {{{ */ + foreach($list as $i=>$item) { + if(get_class($item) == get_class($object) && $item->getID() == $object->getID()) + return $i; + } + return false; + } /* }}} */ + + /** + * Checks if date conforms to a given format + * + * @param string $date date to be checked + * @param string $format format of date. Will default to 'Y-m-d H:i:s' if + * format is not given. + * @return boolean true if date is in propper format, otherwise false + */ + static function checkDate($date, $format='Y-m-d H:i:s') { /* {{{ */ + $d = DateTime::createFromFormat($format, $date); + return $d && $d->format($format) == $date; + } /* }}} */ + + /** + * Filter out objects which are not accessible in a given mode by a user. + * + * The list of objects to be checked can be of any class, but has to have + * a method getAccessMode($user) which checks if the given user has at + * least access rights to the object as passed in $minMode. + * + * This function can be used for documents and folders and calls + * {@link SeedDMS_Core_Folder::getAccessMode()} or + * {@link SeedDMS_Core_Document::getAccessMode()}. A document is also + * filtered out if it has no latest content, which can happen if access + * on documents in a certain state has been restricted. + * + * @param array $objArr list of objects (either documents or folders) + * @param object $user user for which access is checked + * @param integer $minMode minimum access mode required (M_ANY, M_NONE, + * M_READ, M_READWRITE, M_ALL) + * @return array filtered list of objects + */ + static function filterAccess($objArr, $user, $minMode) { /* {{{ */ + if (!is_array($objArr)) { + return array(); + } + $newArr = array(); + foreach ($objArr as $obj) { + if ($obj->getAccessMode($user) >= $minMode) { + $dms = $obj->_dms; + if(get_class($obj) == $dms->getClassname('document')) { + if($obj->getLatestContent()) + array_push($newArr, $obj); + } else { + array_push($newArr, $obj); + } + } + } + return $newArr; + } /* }}} */ + + /** + * Filter out users which cannot access an object in a given mode. + * + * The list of users to be checked can be of any class, but has to have + * a method getAccessMode($user) which checks if a user has at least + * access rights as passed in $minMode. + * + * @param object $obj object that shall be accessed + * @param array $users list of users which are to check for sufficient + * access rights + * @param integer $minMode minimum access right on the object for each user + * (M_ANY, M_NONE, M_READ, M_READWRITE, M_ALL) + * @return array filtered list of users + */ + static function filterUsersByAccess($obj, $users, $minMode) { /* {{{ */ + $newArr = array(); + foreach ($users as $currUser) { + if ($obj->getAccessMode($currUser) >= $minMode) + array_push($newArr, $currUser); + } + return $newArr; + } /* }}} */ + + /** + * Filter out document links which can not be accessed by a given user + * + * Returns a filtered list of links which are accessible by the + * given user. A link is only accessible, if it is publically visible, + * owned by the user, or the accessing user is an administrator. + * + * @param array $links list of objects of type SeedDMS_Core_DocumentLink + * @param object $user user for which access is being checked + * @return array filtered list of links + */ + static function filterDocumentLinks($user, $links) { /* {{{ */ + $tmp = array(); + foreach ($links as $link) + if ($link->isPublic() || ($link->getUser()->getID() == $user->getID()) || $user->isAdmin()) + array_push($tmp, $link); + return $tmp; + } /* }}} */ + + /** + * Merge access lists + * + * Merges two access lists. Objects of the second list will override objects + * in the first list. + * + * @param array $first list of access rights as returned by + * SeedDMS_Core_Document:: getAccessList() or SeedDMS_Core_Folder::getAccessList() + * @param array $secont list of access rights + * @return array merged list + */ + static function mergeAccessLists($first, $second) { /* {{{ */ + if($first && !$second) + return $first; + if(!$first && $second) + return $second; + + $tmp = array('users'=>array(), 'groups'=>array()); + if(!isset($first['users']) || !isset($first['groups']) || + !isset($second['users']) || !isset($second['groups'])) + return false; + + foreach ($first['users'] as $f) { + $new = $f; + foreach ($second['users'] as $i=>$s) { + if($f->getUserID() == $s->getUserID()) { + $new = $s; + unset($second['users'][$i]); + break; + } + } + array_push($tmp['users'], $new); + } + foreach ($seconf['users'] as $f) { + array_push($tmp['users'], $f); + } + + foreach ($first['groups'] as $f) { + $new = $f; + foreach ($second['groups'] as $i=>$s) { + if($f->getGroupID() == $s->getGroupID()) { + $new = $s; + unset($second['groups'][$i]); + break; + } + } + array_push($tmp['groups'], $new); + } + foreach ($second['groups'] as $f) { + array_push($tmp['groups'], $f); + } + + return $tmp; + } /* }}} */ + + /** + * Create a new instance of the dms + * + * @param object $db object of class {@link SeedDMS_Core_DatabaseAccess} + * to access the underlying database + * @param string $contentDir path in filesystem containing the data store + * all document contents is stored + * @return object instance of {@link SeedDMS_Core_DMS} + */ + function __construct($db, $contentDir) { /* {{{ */ + $this->db = $db; + if(substr($contentDir, -1) == '/') + $this->contentDir = $contentDir; + else + $this->contentDir = $contentDir.'/'; + $this->rootFolderID = 1; + $this->maxDirID = 0; //31998; + $this->forceRename = false; + $this->enableConverting = false; + $this->convertFileTypes = array(); + $this->noReadForStatus = array(); + $this->classnames = array(); + $this->classnames['folder'] = 'SeedDMS_Core_Folder'; + $this->classnames['document'] = 'SeedDMS_Core_Document'; + $this->classnames['documentcontent'] = 'SeedDMS_Core_DocumentContent'; + $this->classnames['user'] = 'SeedDMS_Core_User'; + $this->classnames['role'] = 'SeedDMS_Core_Role'; + $this->classnames['group'] = 'SeedDMS_Core_Group'; + $this->classnames['attributedefinitiongroup'] = 'SeedDMS_Core_AttributeDefinitionGroup'; + $this->classnames['transmittal'] = 'SeedDMS_Core_Transmittal'; + $this->classnames['transmittalitem'] = 'SeedDMS_Core_TransmittalItem'; + $this->callbacks = array(); + $this->version = '@package_version@'; + if($this->version[0] == '@') + $this->version = '5.1.2'; + } /* }}} */ + + /** + * Return class name of instantiated objects + * + * This method returns the class name of those objects being instatiated + * by the dms. Each class has an internal place holder, which must be + * passed to function. + * + * @param string placeholder (can be one of 'folder', 'document', + * 'documentcontent', 'user', 'group' + * + * @return string/boolean name of class or false if placeholder is invalid + */ + function getClassname($objectname) { /* {{{ */ + if(isset($this->classnames[$objectname])) + return $this->classnames[$objectname]; + else + return false; + } /* }}} */ + + /** + * Set class name of instantiated objects + * + * This method sets the class name of those objects being instatiated + * by the dms. It is mainly used to create a new class (possible + * inherited from one of the available classes) implementing new + * features. The method should be called in the postInitDMS hook. + * + * @param string placeholder (can be one of 'folder', 'document', + * 'documentcontent', 'user', 'group' + * @param string name of class + * + * @return string/boolean name of old class or false if not set + */ + function setClassname($objectname, $classname) { /* {{{ */ + if(isset($this->classnames[$objectname])) + $oldclass = $this->classnames[$objectname]; + else + $oldclass = false; + $this->classnames[$objectname] = $classname; + return $oldclass; + } /* }}} */ + + /** + * Return database where meta data is stored + * + * This method returns the database object as it was set by the first + * parameter of the constructor. + * + * @return object database + */ + function getDB() { /* {{{ */ + return $this->db; + } /* }}} */ + + /** + * Return the database version + * + * @return array array with elements major, minor, subminor, date + */ + function getDBVersion() { /* {{{ */ + $tbllist = $this->db->TableList(); + $tbllist = explode(',',strtolower(join(',',$tbllist))); + if(!array_search('tblversion', $tbllist)) + return false; + $queryStr = "SELECT * FROM tblVersion order by major,minor,subminor limit 1"; + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + if (count($resArr) != 1) + return false; + $resArr = $resArr[0]; + return $resArr; + } /* }}} */ + + /** + * Check if the version in the database is the same as of this package + * Only the major and minor version number will be checked. + * + * @return boolean returns false if versions do not match, but returns + * true if version matches or table tblVersion does not exists. + */ + function checkVersion() { /* {{{ */ + $tbllist = $this->db->TableList(); + $tbllist = explode(',',strtolower(join(',',$tbllist))); + if(!array_search('tblversion', $tbllist)) + return true; + $queryStr = "SELECT * FROM tblVersion order by major,minor,subminor limit 1"; + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + if (count($resArr) != 1) + return false; + $resArr = $resArr[0]; + $ver = explode('.', $this->version); + if(($resArr['major'] != $ver[0]) || ($resArr['minor'] != $ver[1])) + return false; + return true; + } /* }}} */ + + /** + * Set id of root folder + * This function must be called right after creating an instance of + * {@link SeedDMS_Core_DMS} + * + * @param interger $id id of root folder + */ + function setRootFolderID($id) { /* {{{ */ + $this->rootFolderID = $id; + } /* }}} */ + + /** + * Set maximum number of subdirectories per directory + * + * The value of maxDirID is quite crucial, because each document is + * stored within a directory in the filesystem. Consequently, there can be + * a maximum number of documents, because depending on the file system + * the maximum number of subdirectories is limited. Since version 3.3.0 of + * SeedDMS an additional directory level has been introduced, which + * will be created when maxDirID is not 0. All documents + * from 1 to maxDirID-1 will be saved in 1/, documents from maxDirID + * to 2*maxDirID-1 are stored in 2/ and so on. + * + * Modern file systems like ext4 do not have any restrictions on the number + * of subdirectories anymore. Therefore it is best if this parameter is + * set to 0. Never change this parameter if documents has already been + * created. + * + * This function must be called right after creating an instance of + * {@link SeedDMS_Core_DMS} + * + * @param interger $id id of root folder + */ + function setMaxDirID($id) { /* {{{ */ + $this->maxDirID = $id; + } /* }}} */ + + /** + * Get root folder + * + * @return object/boolean return the object of the root folder or false if + * the root folder id was not set before with {@link setRootFolderID}. + */ + function getRootFolder() { /* {{{ */ + if(!$this->rootFolderID) return false; + return $this->getFolder($this->rootFolderID); + } /* }}} */ + + function setEnableConverting($enable) { /* {{{ */ + $this->enableConverting = $enable; + } /* }}} */ + + function setConvertFileTypes($types) { /* {{{ */ + $this->convertFileTypes = $types; + } /* }}} */ + + function setViewOnlineFileTypes($types) { /* {{{ */ + $this->viewOnlineFileTypes = $types; + } /* }}} */ + + function setForceRename($enable) { /* {{{ */ + $this->forceRename = $enable; + } /* }}} */ + + /** + * Set the logged in user + * + * If user authentication was done externally, this function can + * be used to tell the dms who is currently logged in. + * + * @param object $user + * + */ + function setUser($user) { /* {{{ */ + $this->user = $user; + } /* }}} */ + + /** + * Get the logged in user + * + * If user authentication was done externally, this function can + * be used to tell the dms who is currently logged in. + * + * @return object $user + * + */ + function getLoggedInUser() { /* {{{ */ + return $this->user; + } /* }}} */ + + /** + * Return a document by its id + * + * This function retrieves a document from the database by its id. + * + * @param integer $id internal id of document + * @return object instance of {@link SeedDMS_Core_Document} or false + */ + function getDocument($id) { /* {{{ */ + $classname = $this->classnames['document']; + return $classname::getInstance($id, $this); + } /* }}} */ + + /** + * Returns all documents of a given user + * + * @param object $user + * @return array list of documents + */ + function getDocumentsByUser($user) { /* {{{ */ + return $user->getDocuments(); + } /* }}} */ + + /** + * Returns all documents locked by a given user + * + * @param object $user + * @return array list of documents + */ + function getDocumentsLockedByUser($user) { /* {{{ */ + return $user->getDocumentsLocked(); + } /* }}} */ + + /** + * Returns a document by its name + * + * This function searches a document by its name and restricts the search + * to given folder if passed as the second parameter. + * + * @param string $name + * @param object $folder + * @return object/boolean found document or false + */ + function getDocumentByName($name, $folder=null) { /* {{{ */ + if (!$name) return false; + + $queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser` ". + "FROM `tblDocuments` ". + "LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ". + "WHERE `tblDocuments`.`name` = " . $this->db->qstr($name); + if($folder) + $queryStr .= " AND `tblDocuments`.`folder` = ". $folder->getID(); + $queryStr .= " LIMIT 1"; + + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + if(!$resArr) + return false; + + $row = $resArr[0]; + $document = new $this->classnames['document']($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]); + $document->setDMS($this); + return $document; + } /* }}} */ + + /** + * Return a document content by its id + * + * This function retrieves a document content from the database by its id. + * + * @param integer $id internal id of document content + * @return object instance of {@link SeedDMS_Core_DocumentContent} or false + */ + function getDocumentContent($id) { /* {{{ */ + if (!is_numeric($id)) return false; + + $queryStr = "SELECT * FROM tblDocumentContent WHERE id = ".(int) $id; + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + if (count($resArr) != 1) + return false; + $row = $resArr[0]; + + $document = $this->getDocument($row['document']); + $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']); + return $version; + } /* }}} */ + + /** + * Returns all documents with a predefined search criteria + * + * The records return have the following elements + * + * From Table tblDocuments + * [id] => id of document + * [name] => name of document + * [comment] => comment of document + * [date] => timestamp of creation date of document + * [expires] => timestamp of expiration date of document + * [owner] => user id of owner + * [folder] => id of parent folder + * [folderList] => column separated list of folder ids, e.g. :1:41: + * [inheritAccess] => 1 if access is inherited + * [defaultAccess] => default access mode + * [locked] => always -1 (TODO: is this field still used?) + * [keywords] => keywords of document + * [sequence] => sequence of document + * + * From Table tblDocumentLocks + * [lockUser] => id of user locking the document + * + * From Table tblDocumentStatusLog + * [version] => latest version of document + * [statusID] => id of latest status log + * [documentID] => id of document + * [status] => current status of document + * [statusComment] => comment of current status + * [statusDate] => datetime when the status was entered, e.g. 2014-04-17 21:35:51 + * [userID] => id of user who has initiated the status change + * + * From Table tblUsers + * [ownerName] => name of owner of document + * [statusName] => name of user who has initiated the status change + * + * @param string $listtype type of document list, can be 'AppRevByMe', + * 'AppRevOwner', 'ReceiptByMe', 'ReviseByMe', 'LockedByMe', 'MyDocs' + * @param object $param1 user + * @param string $param2 set to true + * if 'AppRevByMe', 'ReviseByMe', 'ReceiptByMe' shall return even documents + * І have already taken care of. + * @param string $param3 sort list by this field + * @param string $param4 order direction + * @return array list of documents records + */ + function getDocumentList($listtype, $param1=null, $param2=false, $param3='', $param4='') { /* {{{ */ + /* The following query will get all documents and lots of additional + * information. It requires the two temporary tables ttcontentid and + * ttstatid. + */ + if (!$this->db->createTemporaryTable("ttstatid") || !$this->db->createTemporaryTable("ttcontentid")) { + return false; + } + /* The following statement retrieves the status of the last version of all + * documents. It must be restricted by further where clauses. + */ + $queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser`, ". + "`tblDocumentContent`.`version`, `tblDocumentStatus`.*, `tblDocumentStatusLog`.`status`, ". + "`tblDocumentStatusLog`.`comment` AS `statusComment`, `tblDocumentStatusLog`.`date` as `statusDate`, ". + "`tblDocumentStatusLog`.`userID`, `oTbl`.`fullName` AS `ownerName`, `sTbl`.`fullName` AS `statusName` ". + "FROM `tblDocumentContent` ". + "LEFT JOIN `tblDocuments` ON `tblDocuments`.`id` = `tblDocumentContent`.`document` ". + "LEFT JOIN `tblDocumentStatus` ON `tblDocumentStatus`.`documentID` = `tblDocumentContent`.`document` ". + "LEFT JOIN `tblDocumentStatusLog` ON `tblDocumentStatusLog`.`statusID` = `tblDocumentStatus`.`statusID` ". + "LEFT JOIN `ttstatid` ON `ttstatid`.`maxLogID` = `tblDocumentStatusLog`.`statusLogID` ". + "LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentStatus`.`version` AND `ttcontentid`.`document` = `tblDocumentStatus`.`documentID` ". + "LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ". + "LEFT JOIN `tblUsers` AS `oTbl` on `oTbl`.`id` = `tblDocuments`.`owner` ". + "LEFT JOIN `tblUsers` AS `sTbl` on `sTbl`.`id` = `tblDocumentStatusLog`.`userID` ". + "WHERE `ttstatid`.`maxLogID`=`tblDocumentStatusLog`.`statusLogID` ". + "AND `ttcontentid`.`maxVersion` = `tblDocumentContent`.`version` "; + + switch($listtype) { + case 'AppRevByMe': // Documents I have to review/approve {{{ + $user = $param1; + // Get document list for the current user. + $reviewStatus = $user->getReviewStatus(); + $approvalStatus = $user->getApprovalStatus(); + + // Create a comma separated list of all the documentIDs whose information is + // required. + // Take only those documents into account which hasn't be touched by the user + $dList = array(); + foreach ($reviewStatus["indstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + foreach ($reviewStatus["grpstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + foreach ($approvalStatus["indstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + foreach ($approvalStatus["grpstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + $docCSV = ""; + foreach ($dList as $d) { + $docCSV .= (strlen($docCSV)==0 ? "" : ", ")."'".$d."'"; + } + + if (strlen($docCSV)>0) { + $queryStr .= "AND `tblDocumentStatusLog`.`status` IN (".S_DRAFT_REV.", ".S_DRAFT_APP.", ".S_EXPIRED.") ". + "AND `tblDocuments`.`id` IN (" . $docCSV . ") ". + "ORDER BY `statusDate` DESC"; + } else { + $queryStr = ''; + } + break; // }}} + case 'ReviewByMe': // Documents I have to review {{{ + $user = $param1; + // Get document list for the current user. + $reviewStatus = $user->getReviewStatus(); + + // Create a comma separated list of all the documentIDs whose information is + // required. + // Take only those documents into account which hasn't be touched by the user + // ($st["status"]==0) + $dList = array(); + foreach ($reviewStatus["indstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + foreach ($reviewStatus["grpstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + $docCSV = ""; + foreach ($dList as $d) { + $docCSV .= (strlen($docCSV)==0 ? "" : ", ")."'".$d."'"; + } + + if (strlen($docCSV)>0) { + $queryStr .= "AND `tblDocumentStatusLog`.`status` IN (".S_DRAFT_REV.", ".S_EXPIRED.") ". + "AND `tblDocuments`.`id` IN (" . $docCSV . ") ". + "ORDER BY `statusDate` DESC"; + } else { + $queryStr = ''; + } + break; // }}} + case 'ApproveByMe': // Documents I have to approve {{{ + $user = $param1; + // Get document list for the current user. + $approvalStatus = $user->getApprovalStatus(); + + // Create a comma separated list of all the documentIDs whose information is + // required. + // Take only those documents into account which hasn't be touched by the user + // ($st["status"]==0) + $dList = array(); + foreach ($approvalStatus["indstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + foreach ($approvalStatus["grpstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + $docCSV = ""; + foreach ($dList as $d) { + $docCSV .= (strlen($docCSV)==0 ? "" : ", ")."'".$d."'"; + } + + if (strlen($docCSV)>0) { + $queryStr .= "AND `tblDocumentStatusLog`.`status` IN (".S_DRAFT_APP.", ".S_EXPIRED.") ". + "AND `tblDocuments`.`id` IN (" . $docCSV . ") ". + "ORDER BY `statusDate` DESC"; + } else { + $queryStr = ''; + } + break; // }}} + case 'ReceiptByMe': // Documents I have to receipt {{{ + $user = $param1; + // Get document list for the current user. + $receiptStatus = $user->getReceiptStatus(); + + // Create a comma separated list of all the documentIDs whose information is + // required. + // Take only those documents into account which hasn't be touched by the user + // ($st["status"]==0) + $dList = array(); + foreach ($receiptStatus["indstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + foreach ($receiptStatus["grpstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + $docCSV = ""; + foreach ($dList as $d) { + $docCSV .= (strlen($docCSV)==0 ? "" : ", ")."'".$d."'"; + } + + if (strlen($docCSV)>0) { + $queryStr .= "AND `tblDocuments`.`id` IN (" . $docCSV . ") ". + "ORDER BY `statusDate` DESC"; + } else { + $queryStr = ''; + } + break; // }}} + case 'ReviseByMe': // Documents I have to receipt {{{ + $user = $param1; + // Get document list for the current user. + $revisionStatus = $user->getRevisionStatus(); + + // Create a comma separated list of all the documentIDs whose information is + // required. + $dList = array(); + foreach ($revisionStatus["indstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + foreach ($revisionStatus["grpstatus"] as $st) { + if (($st["status"]==0 || $param2) && !in_array($st["documentID"], $dList)) { + $dList[] = $st["documentID"]; + } + } + $docCSV = ""; + foreach ($dList as $d) { + $docCSV .= (strlen($docCSV)==0 ? "" : ", ")."'".$d."'"; + } + + if (strlen($docCSV)>0) { + $queryStr .= "AND `tblDocuments`.`id` IN (" . $docCSV . ") ". + "ORDER BY `statusDate` DESC"; + } else { + $queryStr = ''; + } + break; // }}} + case 'WorkflowByMe': // Documents I to trigger in Worklflow {{{ + $user = $param1; + // Get document list for the current user. + $workflowStatus = $user->getWorkflowStatus(); + + // Create a comma separated list of all the documentIDs whose information is + // required. + $dList = array(); + foreach ($workflowStatus["u"] as $st) { + if (!in_array($st["document"], $dList)) { + $dList[] = $st["document"]; + } + } + foreach ($workflowStatus["g"] as $st) { + if (!in_array($st["document"], $dList)) { + $dList[] = $st["document"]; + } + } + $docCSV = ""; + foreach ($dList as $d) { + $docCSV .= (strlen($docCSV)==0 ? "" : ", ")."'".$d."'"; + } + + if (strlen($docCSV)>0) { + $queryStr .= + //"AND `tblDocumentStatusLog`.`status` IN (".S_IN_WORKFLOW.", ".S_EXPIRED.") ". + "AND `tblDocuments`.`id` IN (" . $docCSV . ") ". + "ORDER BY `statusDate` DESC"; + } else { + $queryStr = ''; + } + break; // }}} + case 'AppRevOwner': // Documents waiting for review/approval I'm owning {{{ + $user = $param1; + $orderby = $param3; + if($param4 == 'desc') + $orderdir = 'DESC'; + else + $orderdir = 'ASC'; + $queryStr .= "AND `tblDocuments`.`owner` = '".$user->getID()."' ". + "AND `tblDocumentStatusLog`.`status` IN (".S_DRAFT_REV.", ".S_DRAFT_APP.") "; + 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 .= "AND `tblDocuments`.`owner` = '".$user->getID()."' ". +// "AND `tblDocumentStatusLog`.`status` IN (".S_DRAFT_REV.", ".S_DRAFT_APP.") ". +// "ORDER BY `statusDate` DESC"; + break; // }}} + case 'RejectOwner': // Documents that has been rejected and I'm owning {{{ + $user = $param1; + $queryStr .= "AND `tblDocuments`.`owner` = '".$user->getID()."' ". + "AND `tblDocumentStatusLog`.`status` IN (".S_REJECTED.") ". + "ORDER BY `statusDate` DESC"; + break; // }}} + case 'LockedByMe': // Documents locked by me {{{ + $user = $param1; + $queryStr .= "AND `tblDocumentLocks`.`userID` = '".$user->getID()."' ". + "ORDER BY `statusDate` DESC"; + break; // }}} + case 'WorkflowOwner': // Documents waiting for workflow trigger I'm owning {{{ + $user = $param1; + $queryStr .= "AND `tblDocuments`.`owner` = '".$user->getID()."' ". + "AND `tblDocumentStatusLog`.`status` IN (".S_IN_WORKFLOW.") ". + "ORDER BY `statusDate` DESC"; + break; // }}} + case 'MyDocs': // Documents owned by me {{{ + $user = $param1; + $orderby = $param3; + if($param4 == 'desc') + $orderdir = 'DESC'; + else + $orderdir = 'ASC'; + $queryStr .= "AND `tblDocuments`.`owner` = '".$user->getID()."' "; + 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; + break; // }}} + case 'CheckedOutByMe': // Documents I have checked out {{{ + $user = $param1; + + $qs = 'SELECT document FROM tblDocumentCheckOuts WHERE userID='.$user->getID(); + $ra = $this->db->getResultArray($qs); + if (is_bool($ra) && !$ra) { + return false; + } + $docs = array(); + foreach($ra as $d) { + $docs[] = $d['document']; + } + + if ($docs) { + $queryStr .= "AND `tblDocuments`.`id` IN (" . implode(',', $docs) . ") ". + "ORDER BY `statusDate` DESC"; + } else { + $queryStr = ''; + } + break; // }}} + } + + if($queryStr) { + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) { + return false; + } + /* + $documents = array(); + foreach($resArr as $row) + $documents[] = $this->getDocument($row["id"]); + */ + } else { + return array(); + } + + return $resArr; + } /* }}} */ + + function makeTimeStamp($hour, $min, $sec, $year, $month, $day) { /* {{{ */ + $thirtyone = array (1, 3, 5, 7, 8, 10, 12); + $thirty = array (4, 6, 9, 11); + + // Very basic check that the terms are valid. Does not fail for illegal + // dates such as 31 Feb. + if (!is_numeric($hour) || !is_numeric($min) || !is_numeric($sec) || !is_numeric($year) || !is_numeric($month) || !is_numeric($day) || $month<1 || $month>12 || $day<1 || $day>31 || $hour<0 || $hour>23 || $min<0 || $min>59 || $sec<0 || $sec>59) { + return false; + } + $year = (int) $year; + $month = (int) $month; + $day = (int) $day; + + if (array_search($month, $thirtyone)) { + $max=31; + } + else if (array_search($month, $thirty)) { + $max=30; + } + else { + $max=(($year % 4 == 0) && ($year % 100 != 0 || $year % 400 == 0)) ? 29 : 28; + } + + // If the date falls out of bounds, set it to the maximum for the given + // month. Makes assumption about the user's intention, rather than failing + // for absolutely everything. + if ($day>$max) { + $day=$max; + } + + return mktime($hour, $min, $sec, $month, $day, $year); + } /* }}} */ + + /* + * Search the database for documents + * + * Note: the creation date will be used to check againts the + * date saved with the document + * or folder. The modification date will only be used for documents. It + * is checked against the creation date of the document content. This + * meanѕ that updateѕ of a document will only result in a searchable + * modification if a new version is uploaded. + * + * @param query string seach query with space separated words + * @param limit integer number of items in result set + * @param offset integer index of first item in result set + * @param logicalmode string either AND or OR + * @param searchin array() list of fields to search in + * 1 = keywords, 2=name, 3=comment, 4=attributes + * @param startFolder object search in the folder only (null for root folder) + * @param owner object search for documents owned by this user + * @param status array list of status + * @param creationstartdate array search for documents created after this date + * @param creationenddate array search for documents created before this date + * @param modificationstartdate array search for documents modified after this date + * @param modificationenddate array search for documents modified before this date + * @param categories array list of categories the documents must have assigned + * @param attributes array list of attributes. The key of this array is the + * attribute definition id. The value of the array is the value of the + * attribute. If the attribute may have multiple values it must be an array. + * @param mode int decide whether to search for documents/folders + * 0x1 = documents only + * 0x2 = folders only + * 0x3 = both + * @param expirationstartdate array search for documents expiring after this date + * @param expirationenddate array search for documents expiring before this date + * @return array containing the elements total and docs + */ + 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()) { /* {{{ */ + // Split the search string into constituent keywords. + $tkeys=array(); + if (strlen($query)>0) { + $tkeys = preg_split("/[\t\r\n ,]+/", $query); + } + + // if none is checkd search all + if (count($searchin)==0) + $searchin=array(1, 2, 3, 4); + + /*--------- Do it all over again for folders -------------*/ + $totalFolders = 0; + if($mode & 0x2) { + $searchKey = ""; + + $classname = $this->classnames['folder']; + $searchFields = $classname::getSearchFields($searchin); + + if (count($searchFields)>0) { + foreach ($tkeys as $key) { + $key = trim($key); + if (strlen($key)>0) { + $searchKey = (strlen($searchKey)==0 ? "" : $searchKey." ".$logicalmode." ")."(".implode(" like ".$this->db->qstr("%".$key."%")." OR ", $searchFields)." like ".$this->db->qstr("%".$key."%").")"; + } + } + } + + // Check to see if the search has been restricted to a particular sub-tree in + // the folder hierarchy. + $searchFolder = ""; + if ($startFolder) { + $searchFolder = "`tblFolders`.`folderList` LIKE '%:".$startFolder->getID().":%'"; + } + + // Check to see if the search has been restricted to a particular + // document owner. + $searchOwner = ""; + if ($owner) { + if(is_array($owner)) { + $ownerids = array(); + foreach($owner as $o) + $ownerids[] = $o->getID(); + if($ownerids) + $searchOwner = "`tblFolders`.`owner` IN (".implode(',', $ownerids).")"; + } else { + $searchOwner = "`tblFolders`.`owner` = '".$owner->getId()."'"; + } + } + + // Check to see if the search has been restricted to a particular + // attribute. + $searchAttributes = array(); + if ($attributes) { + foreach($attributes as $attrdefid=>$attribute) { + if($attribute) { + $attrdef = $this->getAttributeDefinition($attrdefid); + if($attrdef->getObjType() == SeedDMS_Core_AttributeDefinition::objtype_folder || $attrdef->getObjType() == SeedDMS_Core_AttributeDefinition::objtype_all) { + if($valueset = $attrdef->getValueSet()) { + if($attrdef->getMultipleValues()) { + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblFolderAttributes` WHERE `tblFolderAttributes`.`attrdef`=".$attrdefid." AND (`tblFolderAttributes`.`value` like '%".$valueset[0].implode("%' OR `tblFolderAttributes`.`value` like '%".$valueset[0], $attribute)."%') AND `tblFolderAttributes`.`folder`=`tblFolders`.`id`)"; + } else + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblFolderAttributes` WHERE `tblFolderAttributes`.`attrdef`=".$attrdefid." AND `tblFolderAttributes`.`value`='".$attribute."' AND `tblFolderAttributes`.`folder`=`tblFolders`.`id`)"; + } else + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblFolderAttributes` WHERE `tblFolderAttributes`.`attrdef`=".$attrdefid." AND `tblFolderAttributes`.`value` like '%".$attribute."%' AND `tblFolderAttributes`.`folder`=`tblFolders`.`id`)"; + } + } + } + } + + // Is the search restricted to documents created between two specific dates? + $searchCreateDate = ""; + if ($creationstartdate) { + $startdate = SeedDMS_Core_DMS::makeTimeStamp($creationstartdate['hour'], $creationstartdate['minute'], $creationstartdate['second'], $creationstartdate['year'], $creationstartdate["month"], $creationstartdate["day"]); + if ($startdate) { + $searchCreateDate .= "`tblFolders`.`date` >= ".$startdate; + } + } + if ($creationenddate) { + $stopdate = SeedDMS_Core_DMS::makeTimeStamp($creationenddate['hour'], $creationstartdate['minute'], $creationstartdate['second'], $creationenddate["year"], $creationenddate["month"], $creationenddate["day"]); + if ($stopdate) { + if($startdate) + $searchCreateDate .= " AND "; + $searchCreateDate .= "`tblFolders`.`date` <= ".$stopdate; + } + } + + $searchQuery = "FROM ".$classname::getSearchTables()." WHERE 1=1"; + + if (strlen($searchKey)>0) { + $searchQuery .= " AND (".$searchKey.")"; + } + if (strlen($searchFolder)>0) { + $searchQuery .= " AND ".$searchFolder; + } + if (strlen($searchOwner)>0) { + $searchQuery .= " AND (".$searchOwner.")"; + } + if (strlen($searchCreateDate)>0) { + $searchQuery .= " AND (".$searchCreateDate.")"; + } + if ($searchAttributes) { + $searchQuery .= " AND (".implode(" AND ", $searchAttributes).")"; + } + + /* Do not search for folders if not at least a search for a key, + * an owner, or creation date is requested. + */ + if($searchKey || $searchOwner || $searchCreateDate || $searchAttributes) { + // Count the number of rows that the search will produce. + $resArr = $this->db->getResultArray("SELECT COUNT(*) AS num FROM (SELECT DISTINCT `tblFolders`.id ".$searchQuery.") a"); + if ($resArr && isset($resArr[0]) && is_numeric($resArr[0]["num"]) && $resArr[0]["num"]>0) { + $totalFolders = (integer)$resArr[0]["num"]; + } + + // If there are no results from the count query, then there is no real need + // to run the full query. TODO: re-structure code to by-pass additional + // queries when no initial results are found. + + // Only search if the offset is not beyond the number of folders + if($totalFolders > $offset) { + // Prepare the complete search query, including the LIMIT clause. + $searchQuery = "SELECT DISTINCT `tblFolders`.* ".$searchQuery." GROUP BY `tblFolders`.`id`"; + + if($limit) { + $searchQuery .= " LIMIT ".$offset.",".$limit; + } + + // Send the complete search query to the database. + $resArr = $this->db->getResultArray($searchQuery); + } else { + $resArr = array(); + } + + // ------------------- Ausgabe der Ergebnisse ---------------------------- + $numResults = count($resArr); + if ($numResults == 0) { + $folderresult = array('totalFolders'=>$totalFolders, 'folders'=>array()); + } else { + foreach ($resArr as $folderArr) { + $folders[] = $this->getFolder($folderArr['id']); + } + $folderresult = array('totalFolders'=>$totalFolders, 'folders'=>$folders); + } + } else { + $folderresult = array('totalFolders'=>0, 'folders'=>array()); + } + } else { + $folderresult = array('totalFolders'=>0, 'folders'=>array()); + } + + /*--------- Do it all over again for documents -------------*/ + + $totalDocs = 0; + if($mode & 0x1) { + $searchKey = ""; + $searchFields = array(); + if (in_array(1, $searchin)) { + $searchFields[] = "`tblDocuments`.`keywords`"; + } + if (in_array(2, $searchin)) { + $searchFields[] = "`tblDocuments`.`name`"; + } + if (in_array(3, $searchin)) { + $searchFields[] = "`tblDocuments`.`comment`"; + $searchFields[] = "`tblDocumentContent`.`comment`"; + } + if (in_array(4, $searchin)) { + $searchFields[] = "`tblDocumentAttributes`.`value`"; + $searchFields[] = "`tblDocumentContentAttributes`.`value`"; + } + + + if (count($searchFields)>0) { + foreach ($tkeys as $key) { + $key = trim($key); + if (strlen($key)>0) { + $searchKey = (strlen($searchKey)==0 ? "" : $searchKey." ".$logicalmode." ")."(".implode(" like ".$this->db->qstr("%".$key."%")." OR ", $searchFields)." like ".$this->db->qstr("%".$key."%").")"; + } + } + } + + // Check to see if the search has been restricted to a particular sub-tree in + // the folder hierarchy. + $searchFolder = ""; + if ($startFolder) { + $searchFolder = "`tblDocuments`.`folderList` LIKE '%:".$startFolder->getID().":%'"; + } + + // Check to see if the search has been restricted to a particular + // document owner. + $searchOwner = ""; + if ($owner) { + if(is_array($owner)) { + $ownerids = array(); + foreach($owner as $o) + $ownerids[] = $o->getID(); + if($ownerids) + $searchOwner = "`tblDocuments`.`owner` IN (".implode(',', $ownerids).")"; + } else { + $searchOwner = "`tblDocuments`.`owner` = '".$owner->getId()."'"; + } + } + + // Check to see if the search has been restricted to a particular + // document category. + $searchCategories = ""; + if ($categories) { + $catids = array(); + foreach($categories as $category) + $catids[] = $category->getId(); + $searchCategories = "`tblDocumentCategory`.`categoryID` in (".implode(',', $catids).")"; + } + + // Check to see if the search has been restricted to a particular + // attribute. + $searchAttributes = array(); + if ($attributes) { + foreach($attributes as $attrdefid=>$attribute) { + if($attribute) { + $attrdef = $this->getAttributeDefinition($attrdefid); + if($attrdef->getObjType() == SeedDMS_Core_AttributeDefinition::objtype_document || $attrdef->getObjType() == SeedDMS_Core_AttributeDefinition::objtype_all) { + if($valueset = $attrdef->getValueSet()) { + if($attrdef->getMultipleValues()) { + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentAttributes` WHERE `tblDocumentAttributes`.`attrdef`=".$attrdefid." AND (`tblDocumentAttributes`.`value` like '%".$valueset[0].implode("%' OR `tblDocumentAttributes`.`value` like '%".$valueset[0], $attribute)."%') AND `tblDocumentAttributes`.`document` = `tblDocuments`.`id`)"; + } else + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentAttributes` WHERE `tblDocumentAttributes`.`attrdef`=".$attrdefid." AND `tblDocumentAttributes`.`value`='".$attribute."' AND `tblDocumentAttributes`.`document` = `tblDocuments`.`id`)"; + } else + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentAttributes` WHERE `tblDocumentAttributes`.`attrdef`=".$attrdefid." AND `tblDocumentAttributes`.`value` like '%".$attribute."%' AND `tblDocumentAttributes`.`document` = `tblDocuments`.`id`)"; + } elseif($attrdef->getObjType() == SeedDMS_Core_AttributeDefinition::objtype_documentcontent) { + if($attrdef->getValueSet()) { + if($attrdef->getMultipleValues()) { + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentContentAttributes` WHERE `tblDocumentContentAttributes`.`attrdef`=".$attrdefid." AND (`tblDocumentContentAttributes`.`value` like '%".$valueset[0].implode("%' OR `tblDocumentContentAttributes`.`value` like '%".$valueset[0], $attribute)."%') AND `tblDocumentContentAttributes`.`document` = `tblDocumentContent`.`id`)"; + } else { + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentContentAttributes` WHERE `tblDocumentContentAttributes`.`attrdef`=".$attrdefid." AND `tblDocumentContentAttributes`.`value`='".$attribute."' AND `tblDocumentContentAttributes`.content = `tblDocumentContent`.id)"; + } + } else + $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentContentAttributes` WHERE `tblDocumentContentAttributes`.`attrdef`=".$attrdefid." AND `tblDocumentContentAttributes`.`value` like '%".$attribute."%' AND `tblDocumentContentAttributes`.content = `tblDocumentContent`.id)"; + } + } + } + } + + // Is the search restricted to documents created between two specific dates? + $searchCreateDate = ""; + if ($creationstartdate) { + $startdate = SeedDMS_Core_DMS::makeTimeStamp($creationstartdate['hour'], $creationstartdate['minute'], $creationstartdate['second'], $creationstartdate['year'], $creationstartdate["month"], $creationstartdate["day"]); + if ($startdate) { + $searchCreateDate .= "`tblDocuments`.`date` >= ".$startdate; + } + } + if ($creationenddate) { + $stopdate = SeedDMS_Core_DMS::makeTimeStamp($creationenddate['hour'], $creationenddate['minute'], $creationenddate['second'], $creationenddate["year"], $creationenddate["month"], $creationenddate["day"]); + if ($stopdate) { + if($searchCreateDate) + $searchCreateDate .= " AND "; + $searchCreateDate .= "`tblDocuments`.`date` <= ".$stopdate; + } + } + if ($modificationstartdate) { + $startdate = SeedDMS_Core_DMS::makeTimeStamp($modificationstartdate['hour'], $modificationstartdate['minute'], $modificationstartdate['second'], $modificationstartdate['year'], $modificationstartdate["month"], $modificationstartdate["day"]); + if ($startdate) { + if($searchCreateDate) + $searchCreateDate .= " AND "; + $searchCreateDate .= "`tblDocumentContent`.`date` >= ".$startdate; + } + } + if ($modificationenddate) { + $stopdate = SeedDMS_Core_DMS::makeTimeStamp($modificationenddate['hour'], $modificationenddate['minute'], $modificationenddate['second'], $modificationenddate["year"], $modificationenddate["month"], $modificationenddate["day"]); + if ($stopdate) { + if($searchCreateDate) + $searchCreateDate .= " AND "; + $searchCreateDate .= "`tblDocumentContent`.`date` <= ".$stopdate; + } + } + $searchExpirationDate = ''; + if ($expirationstartdate) { + $startdate = SeedDMS_Core_DMS::makeTimeStamp($expirationstartdate['hour'], $expirationstartdate['minute'], $expirationstartdate['second'], $expirationstartdate['year'], $expirationstartdate["month"], $expirationstartdate["day"]); + if ($startdate) { + if($searchExpirationDate) + $searchExpirationDate .= " AND "; + $searchExpirationDate .= "`tblDocuments`.`expires` >= ".$startdate; + } + } + if ($expirationenddate) { + $stopdate = SeedDMS_Core_DMS::makeTimeStamp($expirationenddate['hour'], $expirationenddate['minute'], $expirationenddate['second'], $expirationenddate["year"], $expirationenddate["month"], $expirationenddate["day"]); + if ($stopdate) { + if($searchExpirationDate) + $searchExpirationDate .= " AND "; + $searchExpirationDate .= "`tblDocuments`.`expires` <= ".$stopdate; + } + } + + // ---------------------- Suche starten ---------------------------------- + + // + // Construct the SQL query that will be used to search the database. + // + + if (!$this->db->createTemporaryTable("ttcontentid") || !$this->db->createTemporaryTable("ttstatid")) { + return false; + } + if($reception) { + if (!$this->db->createTemporaryTable("ttreceiptid")) { + return false; + } + } + + $searchQuery = "FROM `tblDocumentContent` ". + "LEFT JOIN `tblDocuments` ON `tblDocuments`.`id` = `tblDocumentContent`.`document` ". + "LEFT JOIN `tblDocumentAttributes` ON `tblDocuments`.`id` = `tblDocumentAttributes`.`document` ". + "LEFT JOIN `tblDocumentContentAttributes` ON `tblDocumentContent`.`id` = `tblDocumentContentAttributes`.`content` ". + "LEFT JOIN `tblDocumentStatus` ON `tblDocumentStatus`.`documentID` = `tblDocumentContent`.`document` ". + "LEFT JOIN `tblDocumentStatusLog` ON `tblDocumentStatusLog`.`statusID` = `tblDocumentStatus`.`statusID` ". + "LEFT JOIN `ttstatid` ON `ttstatid`.`maxLogID` = `tblDocumentStatusLog`.`statusLogID` ". + "LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentStatus`.`version` AND `ttcontentid`.`document` = `tblDocumentStatus`.`documentID` ". + "LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ". + "LEFT JOIN `tblDocumentCategory` ON `tblDocuments`.`id`=`tblDocumentCategory`.`documentID` ". +// "LEFT JOIN `tblDocumentRecipients` ON `tblDocuments`.`id`=`tblDocumentRecipients`.`documentID` ". +// "LEFT JOIN `tblDocumentReceiptLog` ON `tblDocumentRecipients`.`receiptID`=`tblDocumentReceiptLog`.`receiptID` ". +// "LEFT JOIN `ttreceiptid` ON `ttreceiptid`.`maxLogID` = `tblDocumentReceiptLog`.`receiptLogID` ". + "WHERE `ttstatid`.`maxLogID`=`tblDocumentStatusLog`.`statusLogID` ". +// "AND `ttreceiptid`.`maxLogID`=`tblDocumentReceiptLog`.`receiptLogID` ". + "AND `ttcontentid`.`maxVersion` = `tblDocumentContent`.`version`"; + + if (strlen($searchKey)>0) { + $searchQuery .= " AND (".$searchKey.")"; + } + if (strlen($searchFolder)>0) { + $searchQuery .= " AND ".$searchFolder; + } + if (strlen($searchOwner)>0) { + $searchQuery .= " AND (".$searchOwner.")"; + } + if (strlen($searchCategories)>0) { + $searchQuery .= " AND (".$searchCategories.")"; + } + if (strlen($searchCreateDate)>0) { + $searchQuery .= " AND (".$searchCreateDate.")"; + } + if (strlen($searchExpirationDate)>0) { + $searchQuery .= " AND (".$searchExpirationDate.")"; + } + if ($searchAttributes) { + $searchQuery .= " AND (".implode(" AND ", $searchAttributes).")"; + } + + // status + if ($status) { + $searchQuery .= " AND `tblDocumentStatusLog`.`status` IN (".implode(',', $status).")"; + } + + if($reception) { + $searchReception = array(); + /* still waiting for users/groups to acknownledge reception */ + if(in_array("missingaction", $reception)) + $searchReception[] = "b.`status` IN (0)"; + /* document has not been acknowledeged by at least one user/group */ + if(in_array("hasrejection", $reception)) + $searchReception[] = "b.`status` IN (-1)"; + /* document has been acknowledeged by at least one user/group */ + if(in_array("hasacknowledge", $reception)) + $searchReception[] = "b.`status` IN (1)"; + /* document has been acknowledeged by all users/groups !!! not working !!! */ + if(in_array("completeacknowledge", $reception)) + $searchReception[] = "b.`status` NOT IN (-1, 0)"; + if($searchReception) { + $searchQuery .= " AND EXISTS (SELECT NULL FROM `tblDocumentRecipients` a LEFT JOIN `tblDocumentReceiptLog` b ON a.`receiptID`=b.`receiptID` LEFT JOIN `ttreceiptid` c ON c.`maxLogID` = b.`receiptLogID` WHERE "; + $searchQuery .= "c.`maxLogID`=b.`receiptLogID` AND `tblDocuments`.`id` = a.`documentID` "; + $searchQuery .= "AND (".implode(' OR ', $searchReception)."))"; + } + } + + if($searchKey || $searchOwner || $searchCategories || $searchCreateDate || $searchExpirationDate || $searchAttributes || $status || $reception) { + // Count the number of rows that the search will produce. + $resArr = $this->db->getResultArray("SELECT COUNT(*) AS num FROM (SELECT DISTINCT `tblDocuments`.id ".$searchQuery.") a"); + $totalDocs = 0; + if (is_numeric($resArr[0]["num"]) && $resArr[0]["num"]>0) { + $totalDocs = (integer)$resArr[0]["num"]; + } + + // If there are no results from the count query, then there is no real need + // to run the full query. TODO: re-structure code to by-pass additional + // queries when no initial results are found. + + // Prepare the complete search query, including the LIMIT clause. + $searchQuery = "SELECT DISTINCT `tblDocuments`.*, ". + "`tblDocumentContent`.`version`, ". + "`tblDocumentStatusLog`.`status`, `tblDocumentLocks`.`userID` as `lockUser` ".$searchQuery; + + // calculate the remaining entrїes of the current page + // If page is not full yet, get remaining entries + if($limit) { + $remain = $limit - count($folderresult['folders']); + if($remain) { + if($remain == $limit) + $offset -= $totalFolders; + else + $offset = 0; + if($limit) + $searchQuery .= " LIMIT ".$offset.",".$remain; + + // Send the complete search query to the database. + $resArr = $this->db->getResultArray($searchQuery); + } else { + $resArr = array(); + } + } else { + // Send the complete search query to the database. + $resArr = $this->db->getResultArray($searchQuery); + } + + // ------------------- Ausgabe der Ergebnisse ---------------------------- + $numResults = count($resArr); + if ($numResults == 0) { + $docresult = array('totalDocs'=>$totalDocs, 'docs'=>array()); + } else { + foreach ($resArr as $docArr) { + $docs[] = $this->getDocument($docArr['id']); + } + $docresult = array('totalDocs'=>$totalDocs, 'docs'=>$docs); + } + } else { + $docresult = array('totalDocs'=>0, 'docs'=>array()); + } + } else { + $docresult = array('totalDocs'=>0, 'docs'=>array()); + } + + if($limit) { + $totalPages = (integer)(($totalDocs+$totalFolders)/$limit); + if ((($totalDocs+$totalFolders)%$limit) > 0) { + $totalPages++; + } + } else { + $totalPages = 1; + } + + return array_merge($docresult, $folderresult, array('totalPages'=>$totalPages)); + } /* }}} */ + + /** + * Return a folder by its id + * + * This function retrieves a folder from the database by its id. + * + * @param integer $id internal id of folder + * @return object instance of SeedDMS_Core_Folder or false + */ + function getFolder($id) { /* {{{ */ + $classname = $this->classnames['folder']; + return $classname::getInstance($id, $this); + } /* }}} */ + + /** + * Return a folder by its name + * + * This function retrieves a folder from the database by its name. The + * search covers the whole database. If + * the parameter $folder is not null, it will search for the name + * only within this parent folder. It will not be done recursively. + * + * @param string $name name of the folder + * @param object $folder parent folder + * @return object/boolean found folder or false + */ + function getFolderByName($name, $folder=null) { /* {{{ */ + if (!$name) return false; + + $queryStr = "SELECT * FROM tblFolders WHERE name = " . $this->db->qstr($name); + if($folder) + $queryStr .= " AND `parent` = ". $folder->getID(); + $queryStr .= " LIMIT 1"; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + return false; + + $resArr = $resArr[0]; + $folder = new $this->classnames['folder']($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]); + $folder->setDMS($this); + return $folder; + } /* }}} */ + + /** + * Returns a list of folders and error message not linked in the tree + * + * This function checks all folders in the database. + * + * @return array list of errors + */ + function checkFolders() { /* {{{ */ + $queryStr = "SELECT * FROM tblFolders"; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr === false) + return false; + + $cache = array(); + foreach($resArr as $rec) { + $cache[$rec['id']] = array('name'=>$rec['name'], 'parent'=>$rec['parent'], 'folderList'=>$rec['folderList']); + } + $errors = array(); + foreach($cache as $id=>$rec) { + if(!array_key_exists($rec['parent'], $cache) && $rec['parent'] != 0) { + $errors[$id] = array('id'=>$id, 'name'=>$rec['name'], 'parent'=>$rec['parent'], 'msg'=>'Missing parent'); + } else { + $tmparr = explode(':', $rec['folderList']); + array_shift($tmparr); + if(count($tmparr) != count(array_unique($tmparr))) { + $errors[$id] = array('id'=>$id, 'name'=>$rec['name'], 'parent'=>$rec['parent'], 'msg'=>'Duplicate entry in folder list ('.$rec['folderList'].')'); + } + } + } + + return $errors; + } /* }}} */ + + /** + * Returns a list of documents and error message not linked in the tree + * + * This function checks all documents in the database. + * + * @return array list of errors + */ + function checkDocuments() { /* {{{ */ + $queryStr = "SELECT * FROM tblFolders"; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr === false) + return false; + + $fcache = array(); + foreach($resArr as $rec) { + $fcache[$rec['id']] = array('name'=>$rec['name'], 'parent'=>$rec['parent'], 'folderList'=>$rec['folderList']); + } + + $queryStr = "SELECT * FROM tblDocuments"; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr === false) + return false; + + $dcache = array(); + foreach($resArr as $rec) { + $dcache[$rec['id']] = array('name'=>$rec['name'], 'parent'=>$rec['folder'], 'folderList'=>$rec['folderList']); + } + $errors = array(); + foreach($dcache as $id=>$rec) { + if(!array_key_exists($rec['parent'], $fcache) && $rec['parent'] != 0) { + $errors[$id] = array('id'=>$id, 'name'=>$rec['name'], 'parent'=>$rec['parent'], 'msg'=>'Missing parent'); + } else { + $tmparr = explode(':', $rec['folderList']); + array_shift($tmparr); + if(count($tmparr) != count(array_unique($tmparr))) { + $errors[$id] = array('id'=>$id, 'name'=>$rec['name'], 'parent'=>$rec['parent'], 'msg'=>'Duplicate entry in folder list ('.$rec['folderList'].''); + } + } + } + + return $errors; + } /* }}} */ + + /** + * Return a user by its id + * + * This function retrieves a user from the database by its id. + * + * @param integer $id internal id of user + * @return object instance of {@link SeedDMS_Core_User} or false + */ + function getUser($id) { /* {{{ */ + $classname = $this->classnames['user']; + return $classname::getInstance($id, $this); + } /* }}} */ + + /** + * Return a user by its login + * + * This function retrieves a user from the database by its login. + * If the second optional parameter $email is not empty, the user must + * also have the given email. + * + * @param string $login internal login of user + * @param string $email email of user + * @return object instance of {@link SeedDMS_Core_User} or false + */ + function getUserByLogin($login, $email='') { /* {{{ */ + $classname = $this->classnames['user']; + return $classname::getInstance($login, $this, 'name', $email); + } /* }}} */ + + /** + * Return a user by its email + * + * This function retrieves a user from the database by its email. + * It is needed when the user requests a new password. + * + * @param integer $email email address of user + * @return object instance of {@link SeedDMS_Core_User} or false + */ + function getUserByEmail($email) { /* {{{ */ + $classname = $this->classnames['user']; + return $classname::getInstance($email, $this, 'email'); + } /* }}} */ + + /** + * Return list of all users + * + * @return array of instances of {@link SeedDMS_Core_User} or false + */ + function getAllUsers($orderby = '') { /* {{{ */ + $classname = $this->classnames['user']; + return $classname::getAllInstances($orderby, $this); + } /* }}} */ + + /** + * Add a new user + * + * @param string $login login name + * @param string $pwd password of new user + * @param string $email Email of new user + * @param string $language language of new user + * @param string $comment comment of new user + * @param integer $role role of new user (can be 0=normal, 1=admin, 2=guest) + * @param integer $isHidden hide user in all lists, if this is set login + * is still allowed + * @param integer $isDisabled disable user and prevent login + * @return object of {@link SeedDMS_Core_User} + */ + function addUser($login, $pwd, $fullName, $email, $language, $theme, $comment, $role='0', $isHidden=0, $isDisabled=0, $pwdexpiration='', $quota=0, $homefolder=null) { /* {{{ */ + $db = $this->db; + if (is_object($this->getUserByLogin($login))) { + return false; + } + if(is_object($role)) + $role = $role->getID(); + elseif($role == '') + $role = '0'; + if(trim($pwdexpiration) == '') + $pwdexpiration = 'NULL'; + else + $pwdexpiration = $db->qstr($pwdexpiration); + $queryStr = "INSERT INTO tblUsers (login, pwd, fullName, email, language, theme, comment, role, hidden, disabled, pwdExpiration, quota, homefolder) VALUES (".$db->qstr($login).", ".$db->qstr($pwd).", ".$db->qstr($fullName).", ".$db->qstr($email).", '".$language."', '".$theme."', ".$db->qstr($comment).", '".intval($role)."', '".intval($isHidden)."', '".intval($isDisabled)."', ".$pwdexpiration.", '".intval($quota)."', ".($homefolder ? intval($homefolder) : "NULL").")"; + $res = $this->db->getResult($queryStr); + if (!$res) + return false; + + $user = $this->getUser($this->db->getInsertID()); + + /* Check if 'onPostAddUser' callback is set */ + if(isset($this->_dms->callbacks['onPostAddUser'])) { + foreach($this->_dms->callbacks['onPostUser'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $user)) { + } + } + } + + return $user; + } /* }}} */ + + /** + * Get a group by its id + * + * @param integer $id id of group + * @return object/boolean group or false if no group was found + */ + function getGroup($id) { /* {{{ */ + $classname = $this->classnames['group']; + return $classname::getInstance($id, $this, ''); + } /* }}} */ + + /** + * Get a group by its name + * + * @param string $name name of group + * @return object/boolean group or false if no group was found + */ + function getGroupByName($name) { /* {{{ */ + $classname = $this->classnames['group']; + return $classname::getInstance($name, $this, 'name'); + } /* }}} */ + + /** + * Get a list of all groups + * + * @return array array of instances of {@link SeedDMS_Core_Group} + */ + function getAllGroups() { /* {{{ */ + $classname = $this->classnames['group']; + return $classname::getAllInstances('name', $this); + } /* }}} */ + + /** + * Create a new user group + * + * @param string $name name of group + * @param string $comment comment of group + * @return object/boolean instance of {@link SeedDMS_Core_Group} or false in + * case of an error. + */ + function addGroup($name, $comment) { /* {{{ */ + if (is_object($this->getGroupByName($name))) { + return false; + } + + $queryStr = "INSERT INTO tblGroups (name, comment) VALUES (".$this->db->qstr($name).", ".$this->db->qstr($comment).")"; + if (!$this->db->getResult($queryStr)) + return false; + + $group = $this->getGroup($this->db->getInsertID()); + + /* Check if 'onPostAddGroup' callback is set */ + if(isset($this->_dms->callbacks['onPostAddGroup'])) { + foreach($this->_dms->callbacks['onPostAddGroup'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $group)) { + } + } + } + + return $group; + } /* }}} */ + + /** + * Get a role by its id + * + * @param integer $id id of role + * @return object/boolean role or false if no role was found + */ + function getRole($id) { /* {{{ */ + $classname = $this->classnames['role']; + return $classname::getInstance($id, $this); + } /* }}} */ + + /** + * Get a role by its name + * + * @param integer $name name of role + * @return object/boolean role or false if no role was found + */ + function getRoleByName($name) { /* {{{ */ + $classname = $this->classnames['role']; + return $classname::getInstance($name, $this, 'name'); + } /* }}} */ + + /** + * Return list of all roles + * + * @return array of instances of {@link SeedDMS_Core_Role} or false + */ + function getAllRoles($orderby = '') { /* {{{ */ + $classname = $this->classnames['role']; + return $classname::getAllInstances($orderby, $this); + } /* }}} */ + + /** + * Create a new role + * + * @param string $name name of role + * @return object/boolean instance of {@link SeedDMS_Core_Role} or false in + * case of an error. + */ + function addRole($name, $role) { /* {{{ */ + if (is_object($this->getRoleByName($name))) { + return false; + } + + $queryStr = "INSERT INTO tblRoles (name, role) VALUES (".$this->db->qstr($name).", ".$role.")"; + if (!$this->db->getResult($queryStr)) + return false; + + return $this->getRole($this->db->getInsertID()); + } /* }}} */ + + /** + * Get a transmittal by its id + * + * @param integer $id id of transmittal + * @return object/boolean transmittal or false if no group was found + */ + function getTransmittal($id) { /* {{{ */ + $classname = $this->classnames['transmittal']; + return $classname::getInstance($id, $this, ''); + } /* }}} */ + + /** + * Get a transmittal by its name + * + * @param string $name name of transmittal + * @return object/boolean transmittal or false if no group was found + */ + function getTransmittalByName($name) { /* {{{ */ + $classname = $this->classnames['transmittal']; + return $classname::getInstance($name, $this, 'name'); + } /* }}} */ + + /** + * Return list of all transmittals + * + * @return array of instances of {@link SeedDMS_Core_Transmittal} or false + */ + function getAllTransmittals($user=null, $orderby = '') { /* {{{ */ + $classname = $this->classnames['transmittal']; + return $classname::getAllInstances($user, $orderby, $this); + } /* }}} */ + + /** + * Create a new transmittal + * + * @param string $name name of group + * @param string $comment comment of group + * @param object $user user this transmittal belongs to + * @return object/boolean instance of {@link SeedDMS_Core_Transmittal} or + * false in case of an error. + */ + function addTransmittal($name, $comment, $user) { /* {{{ */ + if (is_object($this->getTransmittalByName($name))) { + return false; + } + + $queryStr = "INSERT INTO tblTransmittals (name, comment, userID) VALUES (".$this->db->qstr($name).", ".$this->db->qstr($comment).", ".$user->getID().")"; + if (!$this->db->getResult($queryStr)) + return false; + + return $this->getTransmittal($this->db->getInsertID()); + } /* }}} */ + + function getKeywordCategory($id) { /* {{{ */ + if (!is_numeric($id)) + return false; + + $queryStr = "SELECT * FROM tblKeywordCategories WHERE id = " . (int) $id; + $resArr = $this->db->getResultArray($queryStr); + if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1)) + return false; + + $resArr = $resArr[0]; + $cat = new SeedDMS_Core_Keywordcategory($resArr["id"], $resArr["owner"], $resArr["name"]); + $cat->setDMS($this); + return $cat; + } /* }}} */ + + function getKeywordCategoryByName($name, $userID) { /* {{{ */ + $queryStr = "SELECT * FROM tblKeywordCategories WHERE name = " . $this->db->qstr($name) . " AND owner = " . (int) $userID; + $resArr = $this->db->getResultArray($queryStr); + if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1)) + return false; + + $resArr = $resArr[0]; + $cat = new SeedDMS_Core_Keywordcategory($resArr["id"], $resArr["owner"], $resArr["name"]); + $cat->setDMS($this); + return $cat; + } /* }}} */ + + function getAllKeywordCategories($userIDs = array()) { /* {{{ */ + $queryStr = "SELECT * FROM tblKeywordCategories"; + if ($userIDs) + $queryStr .= " WHERE owner in (".implode(',', $userIDs).")"; + + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + $categories = array(); + foreach ($resArr as $row) { + $cat = new SeedDMS_Core_KeywordCategory($row["id"], $row["owner"], $row["name"]); + $cat->setDMS($this); + array_push($categories, $cat); + } + + return $categories; + } /* }}} */ + + /** + * This function should be replaced by getAllKeywordCategories() + */ + function getAllUserKeywordCategories($userID) { /* {{{ */ + $queryStr = "SELECT * FROM tblKeywordCategories"; + if ($userID != -1) + $queryStr .= " WHERE owner = " . (int) $userID; + + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + $categories = array(); + foreach ($resArr as $row) { + $cat = new SeedDMS_Core_KeywordCategory($row["id"], $row["owner"], $row["name"]); + $cat->setDMS($this); + array_push($categories, $cat); + } + + return $categories; + } /* }}} */ + + function addKeywordCategory($userID, $name) { /* {{{ */ + if (is_object($this->getKeywordCategoryByName($name, $userID))) { + return false; + } + $queryStr = "INSERT INTO tblKeywordCategories (owner, name) VALUES (".(int) $userID.", ".$this->db->qstr($name).")"; + if (!$this->db->getResult($queryStr)) + return false; + + $category = $this->getKeywordCategory($this->db->getInsertID()); + + /* Check if 'onPostAddKeywordCategory' callback is set */ + if(isset($this->_dms->callbacks['onPostAddKeywordCategory'])) { + foreach($this->_dms->callbacks['onPostAddKeywordCategory'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $category)) { + } + } + } + + return $category; + } /* }}} */ + + function getDocumentCategory($id) { /* {{{ */ + if (!is_numeric($id)) + return false; + + $queryStr = "SELECT * FROM tblCategory WHERE id = " . (int) $id; + $resArr = $this->db->getResultArray($queryStr); + if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1)) + return false; + + $resArr = $resArr[0]; + $cat = new SeedDMS_Core_DocumentCategory($resArr["id"], $resArr["name"]); + $cat->setDMS($this); + return $cat; + } /* }}} */ + + function getDocumentCategories() { /* {{{ */ + $queryStr = "SELECT * FROM tblCategory order by name"; + + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + $categories = array(); + foreach ($resArr as $row) { + $cat = new SeedDMS_Core_DocumentCategory($row["id"], $row["name"]); + $cat->setDMS($this); + array_push($categories, $cat); + } + + return $categories; + } /* }}} */ + + /** + * Get a category by its name + * + * The name of a category is by default unique. + * + * @param string $name human readable name of category + * @return object instance of {@link SeedDMS_Core_DocumentCategory} + */ + function getDocumentCategoryByName($name) { /* {{{ */ + if (!$name) return false; + + $queryStr = "SELECT * FROM tblCategory where name=".$this->db->qstr($name); + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + $row = $resArr[0]; + $cat = new SeedDMS_Core_DocumentCategory($row["id"], $row["name"]); + $cat->setDMS($this); + + return $cat; + } /* }}} */ + + function addDocumentCategory($name) { /* {{{ */ + if (is_object($this->getDocumentCategoryByName($name))) { + return false; + } + $queryStr = "INSERT INTO tblCategory (name) VALUES (".$this->db->qstr($name).")"; + if (!$this->db->getResult($queryStr)) + return false; + + $category = $this->getDocumentCategory($this->db->getInsertID()); + + /* Check if 'onPostAddDocumentCategory' callback is set */ + if(isset($this->_dms->callbacks['onPostAddDocumentCategory'])) { + foreach($this->_dms->callbacks['onPostAddDocumentCategory'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $category)) { + } + } + } + + return $category; + } /* }}} */ + + /** + * Get all notifications for a group + * + * deprecated: User {@link SeedDMS_Core_Group::getNotifications()} + * + * @param object $group group for which notifications are to be retrieved + * @param integer $type type of item (T_DOCUMENT or T_FOLDER) + * @return array array of notifications + */ + function getNotificationsByGroup($group, $type=0) { /* {{{ */ + return $group->getNotifications($type); + } /* }}} */ + + /** + * Get all notifications for a user + * + * deprecated: User {@link SeedDMS_Core_User::getNotifications()} + * + * @param object $user user for which notifications are to be retrieved + * @param integer $type type of item (T_DOCUMENT or T_FOLDER) + * @return array array of notifications + */ + function getNotificationsByUser($user, $type=0) { /* {{{ */ + return $user->getNotifications($type); + } /* }}} */ + + /** + * Create a token to request a new password. + * This function will not delete the password but just creates an entry + * in tblUserRequestPassword indicating a password request. + * + * @return string hash value of false in case of an error + */ + function createPasswordRequest($user) { /* {{{ */ + $hash = md5(uniqid(time())); + $queryStr = "INSERT INTO tblUserPasswordRequest (userID, hash, `date`) VALUES (" . $user->getId() . ", " . $this->db->qstr($hash) .", ".$this->db->getCurrentDatetime().")"; + $resArr = $this->db->getResult($queryStr); + if (is_bool($resArr) && !$resArr) return false; + return $hash; + + } /* }}} */ + + /** + * Check if hash for a password request is valid. + * This function searches a previously create password request and + * returns the user. + * + * @param string $hash + */ + function checkPasswordRequest($hash) { /* {{{ */ + /* Get the password request from the database */ + $queryStr = "SELECT * FROM tblUserPasswordRequest where hash=".$this->db->qstr($hash); + $resArr = $this->db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + if (count($resArr) != 1) + return false; + $resArr = $resArr[0]; + + return $this->getUser($resArr['userID']); + + } /* }}} */ + + /** + * Delete a password request + * + * @param string $hash + */ + function deletePasswordRequest($hash) { /* {{{ */ + /* Delete the request, so nobody can use it a second time */ + $queryStr = "DELETE FROM tblUserPasswordRequest WHERE hash=".$this->db->qstr($hash); + if (!$this->db->getResult($queryStr)) + return false; + return true; + } /* }}} */ + + /** + * Return a attribute definition by its id + * + * This function retrieves a attribute definition from the database by + * its id. + * + * @param integer $id internal id of attribute defintion + * @return object instance of {@link SeedDMS_Core_AttributeDefinition} or false + */ + function getAttributeDefinition($id) { /* {{{ */ + if (!is_numeric($id)) + return false; + + $queryStr = "SELECT * FROM tblAttributeDefinitions WHERE id = " . (int) $id; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) return false; + if (count($resArr) != 1) return false; + + $resArr = $resArr[0]; + + $attrdef = new SeedDMS_Core_AttributeDefinition($resArr["id"], $resArr["name"], $resArr["objtype"], $resArr["type"], $resArr["multiple"], $resArr["minvalues"], $resArr["maxvalues"], $resArr["valueset"], $resArr["regex"]); + $attrdef->setDMS($this); + return $attrdef; + } /* }}} */ + + /** + * Return a attribute definition by its name + * + * This function retrieves an attribute def. from the database by its name. + * + * @param string $name internal name of attribute def. + * @return object instance of {@link SeedDMS_Core_AttributeDefinition} or false + */ + function getAttributeDefinitionByName($name) { /* {{{ */ + if (!$name) return false; + + $queryStr = "SELECT * FROM tblAttributeDefinitions WHERE name = " . $this->db->qstr($name); + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) return false; + if (count($resArr) != 1) return false; + + $resArr = $resArr[0]; + + $attrdef = new SeedDMS_Core_AttributeDefinition($resArr["id"], $resArr["name"], $resArr["objtype"], $resArr["type"], $resArr["multiple"], $resArr["minvalues"], $resArr["maxvalues"], $resArr["valueset"], $resArr["regex"]); + $attrdef->setDMS($this); + return $attrdef; + } /* }}} */ + + /** + * Return list of all attributes definitions + * + * @param integer $objtype select those attributes defined for an object type + * @return array of instances of {@link SeedDMS_Core_AttributeDefinition} or false + */ + function getAllAttributeDefinitions($objtype=0) { /* {{{ */ + $queryStr = "SELECT * FROM tblAttributeDefinitions"; + if($objtype) { + if(is_array($objtype)) + $queryStr .= ' WHERE objtype in (\''.implode("','", $objtype).'\')'; + else + $queryStr .= ' WHERE objtype='.intval($objtype); + } + $queryStr .= ' ORDER BY name'; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + $attrdefs = array(); + + for ($i = 0; $i < count($resArr); $i++) { + $attrdef = new SeedDMS_Core_AttributeDefinition($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["objtype"], $resArr[$i]["type"], $resArr[$i]["multiple"], $resArr[$i]["minvalues"], $resArr[$i]["maxvalues"], $resArr[$i]["valueset"], $resArr[$i]["regex"]); + $attrdef->setDMS($this); + $attrdefs[$i] = $attrdef; + } + + return $attrdefs; + } /* }}} */ + + /** + * Add a new attribute definition + * + * @param string $name name of attribute + * @param string $type type of attribute + * @param boolean $multiple set to 1 if attribute has multiple attributes + * @param integer $minvalues minimum number of values + * @param integer $maxvalues maximum number of values if multiple is set + * @param string $valueset list of allowed values (csv format) + * @return object of {@link SeedDMS_Core_User} + */ + function addAttributeDefinition($name, $objtype, $type, $multiple=0, $minvalues=0, $maxvalues=1, $valueset='', $regex='') { /* {{{ */ + if (is_object($this->getAttributeDefinitionByName($name))) { + return false; + } + if(!$type) + return false; + if(trim($valueset)) { + $valuesetarr = array_map('trim', explode($valueset[0], substr($valueset, 1))); + $valueset = $valueset[0].implode($valueset[0], $valuesetarr); + } else { + $valueset = ''; + } + $queryStr = "INSERT INTO tblAttributeDefinitions (name, objtype, type, multiple, minvalues, maxvalues, valueset, regex) VALUES (".$this->db->qstr($name).", ".intval($objtype).", ".intval($type).", ".intval($multiple).", ".intval($minvalues).", ".intval($maxvalues).", ".$this->db->qstr($valueset).", ".$this->db->qstr($regex).")"; + $res = $this->db->getResult($queryStr); + if (!$res) + return false; + + return $this->getAttributeDefinition($this->db->getInsertID()); + } /* }}} */ + + /** + * Get a group by its id + * + * @param integer $id id of group + * @return object/boolean group or false if no group was found + */ + function getAttributeDefinitionGroup($id) { /* {{{ */ + $classname = $this->classnames['attributedefinitiongroup']; + return $classname::getInstance($id, $this, ''); + } /* }}} */ + + /** + * Get a group by its name + * + * @param string $name name of group + * @return object/boolean group or false if no group was found + */ + function getAttributeDefinitionGroupByName($name) { /* {{{ */ + $classname = $this->classnames['attributedefinitiongroup']; + return $classname::getInstance($name, $this, 'name'); + } /* }}} */ + + /** + * Get a list of all groups + * + * @return array array of instances of {@link SeedDMS_Core_Group} + */ + function getAllAttributeDefinitionGroups() { /* {{{ */ + $classname = $this->classnames['attributedefinitiongroup']; + return $classname::getAllInstances('name', $this); + } /* }}} */ + + /** + * Create a new attribute defintion group + * + * @param string $name name of group + * @param string $comment comment of group + * @return object/boolean instance of {@link SeedDMS_Core_AttributeDefinitionGroup} + * or false in case of an error. + */ + function addAttributeDefinitionGroup($name, $comment) { /* {{{ */ + if (is_object($this->getAttributeDefinitionGroupByName($name))) { + return false; + } + + $queryStr = "INSERT INTO tblAttributeDefinitionGroups (name, comment) VALUES (".$this->db->qstr($name).", ".$this->db->qstr($comment).")"; + if (!$this->db->getResult($queryStr)) + return false; + + $group = $this->getAttributeDefinitionGroup($this->db->getInsertID()); + + /* Check if 'onPostAddAttributeDefinitionGroup' callback is set */ + if(isset($this->_dms->callbacks['onPostAddAttributeDefinitionGroup'])) { + foreach($this->_dms->callbacks['onPostAddAttributeDefinitionGroup'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $group)) { + } + } + } + + return $group; + } /* }}} */ + + /** + * Return list of all workflows + * + * @return array of instances of {@link SeedDMS_Core_Workflow} or false + */ + function getAllWorkflows() { /* {{{ */ + $queryStr = "SELECT * FROM tblWorkflows ORDER BY name"; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + $queryStr = "SELECT * FROM tblWorkflowStates ORDER BY name"; + $ressArr = $this->db->getResultArray($queryStr); + + if (is_bool($ressArr) && $ressArr == false) + return false; + + for ($i = 0; $i < count($ressArr); $i++) { + $wkfstates[$ressArr[$i]["id"]] = new SeedDMS_Core_Workflow_State($ressArr[$i]["id"], $ressArr[$i]["name"], $ressArr[$i]["maxtime"], $ressArr[$i]["precondfunc"], $ressArr[$i]["documentstatus"]); + } + + $workflows = array(); + for ($i = 0; $i < count($resArr); $i++) { + $workflow = new SeedDMS_Core_Workflow($resArr[$i]["id"], $resArr[$i]["name"], $wkfstates[$resArr[$i]["initstate"]], $resArr[$i]["layoutdata"]); + $workflow->setDMS($this); + $workflows[$i] = $workflow; + } + + return $workflows; + } /* }}} */ + + /** + * Return workflow by its Id + * + * @param integer $id internal id of workflow + * @return object of instances of {@link SeedDMS_Core_Workflow} or false + */ + function getWorkflow($id) { /* {{{ */ + $queryStr = "SELECT * FROM tblWorkflows WHERE id=".intval($id); + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + return false; + + $initstate = $this->getWorkflowState($resArr[0]['initstate']); + + $workflow = new SeedDMS_Core_Workflow($resArr[0]["id"], $resArr[0]["name"], $initstate, $resArr[0]["layoutdata"]); + $workflow->setDMS($this); + + return $workflow; + } /* }}} */ + + /** + * Return workflow by its name + * + * @param string $name name of workflow + * @return object of instances of {@link SeedDMS_Core_Workflow} or false + */ + function getWorkflowByName($name) { /* {{{ */ + if (!$name) return false; + + $queryStr = "SELECT * FROM tblWorkflows WHERE name=".$this->db->qstr($name); + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + return false; + + $initstate = $this->getWorkflowState($resArr[0]['initstate']); + + $workflow = new SeedDMS_Core_Workflow($resArr[0]["id"], $resArr[0]["name"], $initstate, $resArr[0]["layoutdata"]); + $workflow->setDMS($this); + + return $workflow; + } /* }}} */ + + /** + * Add a new workflow + * + * @param string $name name of workflow + * @param string $initstate initial state of workflow + */ + function addWorkflow($name, $initstate) { /* {{{ */ + $db = $this->db; + if (is_object($this->getWorkflowByName($name))) { + return false; + } + $queryStr = "INSERT INTO tblWorkflows (name, initstate) VALUES (".$db->qstr($name).", ".$initstate->getID().")"; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + return $this->getWorkflow($db->getInsertID()); + } /* }}} */ + + /** + * Return a workflow state by its id + * + * This function retrieves a workflow state from the database by its id. + * + * @param integer $id internal id of workflow state + * @return object instance of {@link SeedDMS_Core_Workflow_State} or false + */ + function getWorkflowState($id) { /* {{{ */ + if (!is_numeric($id)) + return false; + + $queryStr = "SELECT * FROM tblWorkflowStates WHERE id = " . (int) $id; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) return false; + if (count($resArr) != 1) return false; + + $resArr = $resArr[0]; + + $state = new SeedDMS_Core_Workflow_State($resArr["id"], $resArr["name"], $resArr["maxtime"], $resArr["precondfunc"], $resArr["documentstatus"]); + $state->setDMS($this); + return $state; + } /* }}} */ + + /** + * Return workflow state by its name + * + * @param string $name name of workflow state + * @return object of instances of {@link SeedDMS_Core_Workflow_State} or false + */ + function getWorkflowStateByName($name) { /* {{{ */ + if (!$name) return false; + + $queryStr = "SELECT * FROM tblWorkflowStates WHERE name=".$this->db->qstr($name); + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + return false; + + $resArr = $resArr[0]; + + $state = new SeedDMS_Core_Workflow_State($resArr["id"], $resArr["name"], $resArr["maxtime"], $resArr["precondfunc"], $resArr["documentstatus"]); + $state->setDMS($this); + + return $state; + } /* }}} */ + + /** + * Return list of all workflow states + * + * @return array of instances of {@link SeedDMS_Core_Workflow_State} or false + */ + function getAllWorkflowStates() { /* {{{ */ + $queryStr = "SELECT * FROM tblWorkflowStates ORDER BY name"; + $ressArr = $this->db->getResultArray($queryStr); + + if (is_bool($ressArr) && $ressArr == false) + return false; + + $wkfstates = array(); + for ($i = 0; $i < count($ressArr); $i++) { + $wkfstate = new SeedDMS_Core_Workflow_State($ressArr[$i]["id"], $ressArr[$i]["name"], $ressArr[$i]["maxtime"], $ressArr[$i]["precondfunc"], $ressArr[$i]["documentstatus"]); + $wkfstate->setDMS($this); + $wkfstates[$i] = $wkfstate; + } + + return $wkfstates; + } /* }}} */ + + /** + * Add new workflow state + * + * @param string $name name of workflow state + * @param integer $docstatus document status when this state is reached + * @return object instance of new workflow state + */ + function addWorkflowState($name, $docstatus) { /* {{{ */ + $db = $this->db; + if (is_object($this->getWorkflowStateByName($name))) { + return false; + } + $queryStr = "INSERT INTO tblWorkflowStates (name, documentstatus) VALUES (".$db->qstr($name).", ".(int) $docstatus.")"; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + return $this->getWorkflowState($db->getInsertID()); + } /* }}} */ + + /** + * Return a workflow action by its id + * + * This function retrieves a workflow action from the database by its id. + * + * @param integer $id internal id of workflow action + * @return object instance of {@link SeedDMS_Core_Workflow_Action} or false + */ + function getWorkflowAction($id) { /* {{{ */ + if (!is_numeric($id)) + return false; + + $queryStr = "SELECT * FROM tblWorkflowActions WHERE id = " . (int) $id; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) return false; + if (count($resArr) != 1) return false; + + $resArr = $resArr[0]; + + $action = new SeedDMS_Core_Workflow_Action($resArr["id"], $resArr["name"]); + $action->setDMS($this); + return $action; + } /* }}} */ + + /** + * Return a workflow action by its name + * + * This function retrieves a workflow action from the database by its name. + * + * @param string $name name of workflow action + * @return object instance of {@link SeedDMS_Core_Workflow_Action} or false + */ + function getWorkflowActionByName($name) { /* {{{ */ + if (!$name) return false; + + $queryStr = "SELECT * FROM tblWorkflowActions WHERE name = " . $this->db->qstr($name); + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) return false; + if (count($resArr) != 1) return false; + + $resArr = $resArr[0]; + + $action = new SeedDMS_Core_Workflow_Action($resArr["id"], $resArr["name"]); + $action->setDMS($this); + return $action; + } /* }}} */ + + /** + * Return list of workflow action + * + * @return array list of instances of {@link SeedDMS_Core_Workflow_Action} or false + */ + function getAllWorkflowActions() { /* {{{ */ + $queryStr = "SELECT * FROM tblWorkflowActions"; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) + return false; + + $wkfactions = array(); + for ($i = 0; $i < count($resArr); $i++) { + $action = new SeedDMS_Core_Workflow_Action($resArr[$i]["id"], $resArr[$i]["name"]); + $action->setDMS($this); + $wkfactions[$i] = $action; + } + + return $wkfactions; + } /* }}} */ + + /** + * Add new workflow action + * + * @param string $name name of workflow action + * @return object instance new workflow action + */ + function addWorkflowAction($name) { /* {{{ */ + $db = $this->db; + if (is_object($this->getWorkflowActionByName($name))) { + return false; + } + $queryStr = "INSERT INTO tblWorkflowActions (name) VALUES (".$db->qstr($name).")"; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + return $this->getWorkflowAction($db->getInsertID()); + } /* }}} */ + + /** + * Return a workflow transition by its id + * + * This function retrieves a workflow transition from the database by its id. + * + * @param integer $id internal id of workflow transition + * @return object instance of {@link SeedDMS_Core_Workflow_Transition} or false + */ + function getWorkflowTransition($id) { /* {{{ */ + if (!is_numeric($id)) + return false; + + $queryStr = "SELECT * FROM tblWorkflowTransitions WHERE id = " . (int) $id; + $resArr = $this->db->getResultArray($queryStr); + + if (is_bool($resArr) && $resArr == false) return false; + if (count($resArr) != 1) return false; + + $resArr = $resArr[0]; + + $transition = new SeedDMS_Core_Workflow_Transition($resArr["id"], $this->getWorkflow($resArr["workflow"]), $this->getWorkflowState($resArr["state"]), $this->getWorkflowAction($resArr["action"]), $this->getWorkflowState($resArr["nextstate"]), $resArr["maxtime"]); + $transition->setDMS($this); + return $transition; + } /* }}} */ + + /** + * Returns document content which is not linked to a document + * + * This method is for finding straying document content without + * a parent document. In normal operation this should not happen + * but little checks for database consistency and possible errors + * in the application may have left over document content though + * the document is gone already. + */ + function getUnlinkedDocumentContent() { /* {{{ */ + $queryStr = "SELECT * FROM tblDocumentContent WHERE document NOT IN (SELECT id FROM tblDocuments)"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + $versions = array(); + foreach($resArr as $row) { + $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 has no file size set + * + * This method is for finding document content without a file size + * set in the database. The file size of a document content was introduced + * in version 4.0.0 of SeedDMS for implementation of user quotas. + */ + function getNoFileSizeDocumentContent() { /* {{{ */ + $queryStr = "SELECT * FROM tblDocumentContent WHERE fileSize = 0 OR fileSize is null"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + $versions = array(); + foreach($resArr as $row) { + $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'], $row['fileSize'], $row['checksum']); + $versions[] = $version; + } + return $versions; + + } /* }}} */ + + /** + * Returns document content which has no checksum set + * + * This method is for finding document content without a checksum + * set in the database. The checksum of a document content was introduced + * in version 4.0.0 of SeedDMS for finding duplicates. + */ + function getNoChecksumDocumentContent() { /* {{{ */ + $queryStr = "SELECT * FROM tblDocumentContent WHERE checksum = '' OR checksum is null"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + $versions = array(); + foreach($resArr as $row) { + $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 + * + * This method is for finding document content which is available twice + * in the database. The checksum of a document content was introduced + * in version 4.0.0 of SeedDMS for finding duplicates. + */ + function getDuplicateDocumentContent() { /* {{{ */ + $queryStr = "SELECT a.*, b.id as dupid FROM tblDocumentContent a LEFT JOIN tblDocumentContent b ON a.checksum=b.checksum where a.id!=b.id ORDER by a.id"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + $versions = array(); + foreach($resArr as $row) { + $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']); + if(!isset($versions[$row['dupid']])) { + $versions[$row['id']]['content'] = $version; + $versions[$row['id']]['duplicates'] = array(); + } else + $versions[$row['dupid']]['duplicates'][] = $version; + } + return $versions; + + } /* }}} */ + + /** + * Returns statitical information + * + * This method returns all kind of statistical information like + * documents or used space per user, recent activity, etc. + * + * @param string $type type of statistic + * @return array statistical data + */ + function getStatisticalData($type='') { /* {{{ */ + switch($type) { + case 'docsperuser': + $queryStr = "select b.fullname as `key`, count(owner) as total from tblDocuments a left join tblUsers b on a.owner=b.id group by owner"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + return $resArr; + case 'docspermimetype': + $queryStr = "select b.mimeType as `key`, count(mimeType) as total from tblDocuments a left join tblDocumentContent b on a.id=b.document group by b.mimeType"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + return $resArr; + case 'docspercategory': + $queryStr = "select b.name as `key`, count(a.categoryID) as total from tblDocumentCategory a left join tblCategory b on a.categoryID=b.id group by a.categoryID"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + return $resArr; + case 'docsperstatus': + $queryStr = "select b.status as `key`, count(b.status) as total from (select a.id, max(b.version), max(c.statusLogId) as maxlog from tblDocuments a left join tblDocumentStatus b on a.id=b.documentid left join tblDocumentStatusLog c on b.statusid=c.statusid group by a.id, b.version order by a.id, b.statusid) a left join tblDocumentStatusLog b on a.maxlog=b.statusLogId group by b.status"; + $queryStr = "select b.status as `key`, count(b.status) as total from (select a.id, max(c.statusLogId) as maxlog from tblDocuments a left join tblDocumentStatus b on a.id=b.documentid left join tblDocumentStatusLog c on b.statusid=c.statusid group by a.id order by a.id, b.statusid) a left join tblDocumentStatusLog b on a.maxlog=b.statusLogId group by b.status"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + return $resArr; + case 'docspermonth': + $queryStr = "select *, count(`key`) as total from (select ".$this->db->getDateExtract("date", '%Y-%m')." as `key` from tblDocuments) a group by `key` order by `key`"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + return $resArr; + case 'docsaccumulated': + $queryStr = "select *, count(`key`) as total from (select ".$this->db->getDateExtract("date")." as `key` from tblDocuments) a group by `key` order by `key`"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + $sum = 0; + foreach($resArr as &$res) { + $sum += $res['total']; + /* auxially variable $key is need because sqlite returns + * a key '`key`' + */ + $res['key'] = mktime(12, 0, 0, substr($res['key'], 5, 2), substr($res['key'], 8, 2), substr($res['key'], 0, 4)) * 1000; + $res['total'] = $sum; + } + return $resArr; + case 'sizeperuser': + $queryStr = "select c.fullname as `key`, sum(fileSize) as total from tblDocuments a left join tblDocumentContent b on a.id=b.document left join tblUsers c on a.owner=c.id group by a.owner"; + $resArr = $this->db->getResultArray($queryStr); + if (!$resArr) + return false; + + return $resArr; + default: + return array(); + } + } /* }}} */ + + /** + * Returns changes with a period of time + * + * This method returns a list of all changes happened in the database + * within a given period of time. It currently just checks for + * entries in the database tables tblDocumentContent, tblDocumentFiles, + * and tblDocumentStatusLog + * + * @param string $start start date + * @param string $end end date + * @return array list of changes + */ + function getTimeline($startts='', $endts='') { /* {{{ */ + if(!$startts) + $startts = mktime(0, 0, 0); + if(!$endts) + $startts = mktime(24, 0, 0); + $timeline = array(); + + $queryStr = "SELECT document FROM tblDocumentContent WHERE date > ".$startts." AND date < ".$endts; + $resArr = $this->db->getResultArray($queryStr); + if ($resArr === false) + return false; + foreach($resArr as $rec) { + $document = $this->getDocument($rec['document']); + $timeline = array_merge($timeline, $document->getTimeline()); + } + return $timeline; + + } /* }}} */ + + /** + * Set a callback function + * + * @param string $name internal name of callback + * @param mixed $func function name as expected by {call_user_method} + * @param mixed $params parameter passed as the first argument to the + * callback + */ + function setCallback($name, $func, $params=null) { /* {{{ */ + if($name && $func) + $this->callbacks[$name] = array(array($func, $params)); + } /* }}} */ + + /** + * Add a callback function + * + * @param string $name internal name of callback + * @param mixed $func function name as expected by {call_user_method} + * @param mixed $params parameter passed as the first argument to the + * callback + */ + function addCallback($name, $func, $params=null) { /* {{{ */ + if($name && $func) + $this->callbacks[$name][] = array($func, $params); + } /* }}} */ + + /** + * Create an sql dump of the complete database + * + * @param string $filename name of dump file + */ + function createDump($filename) { /* {{{ */ + $h = fopen($filename, "w"); + if(!$h) + return false; + + $tables = $this->db->TableList('TABLES'); + foreach($tables as $table) { + $query = "SELECT * FROM `".$table."`"; + $records = $this->db->getResultArray($query); + fwrite($h,"\n-- TABLE: ".$table."--\n\n"); + foreach($records as $record) { + $values=""; + $i = 1; + foreach ($record as $column) { + if (is_numeric($column)) $values .= $column; + else $values .= $this->db->qstr($column); + + if ($i<(count($record))) $values .= ","; + $i++; + } + + fwrite($h, "INSERT INTO `".$table."` VALUES (".$values.");\n"); + } + } + + fclose($h); + return true; + } /* }}} */ + +} +?> diff --git a/SeedDMS_Core/Core/inc.ClassFolder.php b/SeedDMS_Core/Core/inc.ClassFolder.php new file mode 100644 index 000000000..6c9e84131 --- /dev/null +++ b/SeedDMS_Core/Core/inc.ClassFolder.php @@ -0,0 +1,1747 @@ + + * @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, + * 2010 Matteo Lucarelli, 2010 Uwe Steinmann + * @version Release: @package_version@ + */ + +/** + * Class to represent a folder in the document management system + * + * A folder in SeedDMS is equivalent to a directory in a regular file + * system. It can contain further subfolders and documents. Each folder + * has a single parent except for the root folder which has no parent. + * + * @category DMS + * @package SeedDMS_Core + * @version @version@ + * @author Uwe Steinmann + * @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, + * 2010 Matteo Lucarelli, 2010 Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_Core_Folder extends SeedDMS_Core_Object { + /** + * @var string name of folder + */ + protected $_name; + + /** + * @var integer id of parent folder + */ + protected $_parentID; + + /** + * @var string comment of document + */ + protected $_comment; + + /** + * @var integer id of user who is the owner + */ + protected $_ownerID; + + /** + * @var boolean true if access is inherited, otherwise false + */ + protected $_inheritAccess; + + /** + * @var integer default access if access rights are not inherited + */ + protected $_defaultAccess; + + /** + * @var array list of notifications for users and groups + */ + protected $_readAccessList; + + /** + * @var array list of notifications for users and groups + */ + public $_notifyList; + + /** + * @var integer position of folder within the parent folder + */ + protected $_sequence; + + function __construct($id, $name, $parentID, $comment, $date, $ownerID, $inheritAccess, $defaultAccess, $sequence) { /* {{{ */ + parent::__construct($id); + $this->_id = $id; + $this->_name = $name; + $this->_parentID = $parentID; + $this->_comment = $comment; + $this->_date = $date; + $this->_ownerID = $ownerID; + $this->_inheritAccess = $inheritAccess; + $this->_defaultAccess = $defaultAccess; + $this->_sequence = $sequence; + $this->_notifyList = array(); + } /* }}} */ + + /** + * Return an array of database fields which used for searching + * a term entered in the database search form + * + * @param array $searchin integer list of search scopes (2=name, 3=comment, + * 4=attributes) + * @return array list of database fields + */ + public static function getSearchFields($searchin) { /* {{{ */ + $searchFields = array(); + if (in_array(2, $searchin)) { + $searchFields[] = "`tblFolders`.`name`"; + } + if (in_array(3, $searchin)) { + $searchFields[] = "`tblFolders`.`comment`"; + } + if (in_array(4, $searchin)) { + $searchFields[] = "`tblFolderAttributes`.`value`"; + } + return $searchFields; + } /* }}} */ + + /** + * Return a sql statement with all tables used for searching. + * This must be a syntactically correct left join of all tables. + * + * @return string sql expression for left joining tables + */ + public static function getSearchTables() { /* {{{ */ + $sql = "`tblFolders` LEFT JOIN `tblFolderAttributes` on `tblFolders`.`id`=`tblFolderAttributes`.`folder`"; + return $sql; + } /* }}} */ + + public static function getInstance($id, $dms) { /* {{{ */ + $db = $dms->getDB(); + + $queryStr = "SELECT * FROM tblFolders WHERE id = " . (int) $id; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + else if (count($resArr) != 1) + return false; + + $resArr = $resArr[0]; + $classname = $dms->getClassname('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); + return $folder; + } /* }}} */ + + /* + * Get the name of the folder. + * + * @return string name of folder + */ + public function getName() { return $this->_name; } + + /* + * Set the name of the folder. + * + * @param string $newName set a new name of the folder + */ + public function setName($newName) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblFolders SET name = " . $db->qstr($newName) . " WHERE id = ". $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_name = $newName; + + return true; + } /* }}} */ + + public function getComment() { return $this->_comment; } + + public function setComment($newComment) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblFolders SET comment = " . $db->qstr($newComment) . " WHERE id = ". $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_comment = $newComment; + return true; + } /* }}} */ + + /** + * Return creation date of folder + * + * @return integer unix timestamp of creation date + */ + public function getDate() { /* {{{ */ + return $this->_date; + } /* }}} */ + + /** + * Set creation date of the document + * + * @param integer $date timestamp of creation date. If false then set it + * to the current timestamp + * @return boolean true on success + */ + function setDate($date) { /* {{{ */ + $db = $this->_dms->getDB(); + + if(!$date) + $date = time(); + else { + if(!is_numeric($date)) + return false; + } + + $queryStr = "UPDATE tblFolders SET date = " . (int) $date . " WHERE id = ". $this->_id; + if (!$db->getResult($queryStr)) + return false; + $this->_date = $date; + return true; + } /* }}} */ + + /** + * Returns the parent + * + * @return object parent folder or false if there is no parent folder + */ + public function getParent() { /* {{{ */ + if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) { + return false; + } + + if (!isset($this->_parent)) { + $this->_parent = $this->_dms->getFolder($this->_parentID); + } + return $this->_parent; + } /* }}} */ + + /** + * Check if the folder is subfolder + * + * This function checks if the passed folder is a subfolder of the current + * folder. + * + * @param object $subFolder potential sub folder + * @return boolean true if passes folder is a subfolder + */ + function isSubFolder($subfolder) { /* {{{ */ + $target_path = $subfolder->getPath(); + foreach($target_path as $next_folder) { + // the target folder contains this instance in the parent path + if($this->getID() == $next_folder->getID()) return true; + } + return false; + } /* }}} */ + + /** + * Set a new folder + * + * This function moves a folder from one parent folder into another parent + * folder. It will fail if the root folder is moved. + * + * @param object $newParent new parent folder + * @return boolean true if operation was successful otherwise false + */ + public function setParent($newParent) { /* {{{ */ + $db = $this->_dms->getDB(); + + if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) { + return false; + } + + /* Check if the new parent is the folder to be moved or even + * a subfolder of that folder + */ + if($this->isSubFolder($newParent)) { + return false; + } + + // Update the folderList of the folder + $pathPrefix=""; + $path = $newParent->getPath(); + foreach ($path as $f) { + $pathPrefix .= ":".$f->getID(); + } + if (strlen($pathPrefix)>1) { + $pathPrefix .= ":"; + } + $queryStr = "UPDATE tblFolders SET parent = ".$newParent->getID().", folderList='".$pathPrefix."' WHERE id = ". $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + + $this->_parentID = $newParent->getID(); + $this->_parent = $newParent; + + // Must also ensure that any documents in this folder tree have their + // folderLists updated. + $pathPrefix=""; + $path = $this->getPath(); + foreach ($path as $f) { + $pathPrefix .= ":".$f->getID(); + } + if (strlen($pathPrefix)>1) { + $pathPrefix .= ":"; + } + + /* Update path in folderList for all documents */ + $queryStr = "SELECT `tblDocuments`.`id`, `tblDocuments`.`folderList` FROM `tblDocuments` WHERE `folderList` LIKE '%:".$this->_id.":%'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + foreach ($resArr as $row) { + $newPath = preg_replace("/^.*:".$this->_id.":(.*$)/", $pathPrefix."\\1", $row["folderList"]); + $queryStr="UPDATE `tblDocuments` SET `folderList` = '".$newPath."' WHERE `tblDocuments`.`id` = '".$row["id"]."'"; + $res = $db->getResult($queryStr); + } + + /* Update path in folderList for all documents */ + $queryStr = "SELECT `tblFolders`.`id`, `tblFolders`.`folderList` FROM `tblFolders` WHERE `folderList` LIKE '%:".$this->_id.":%'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + foreach ($resArr as $row) { + $newPath = preg_replace("/^.*:".$this->_id.":(.*$)/", $pathPrefix."\\1", $row["folderList"]); + $queryStr="UPDATE `tblFolders` SET `folderList` = '".$newPath."' WHERE `tblFolders`.`id` = '".$row["id"]."'"; + $res = $db->getResult($queryStr); + } + + return true; + } /* }}} */ + + /** + * Returns the owner + * + * @return object owner of the folder + */ + public function getOwner() { /* {{{ */ + if (!isset($this->_owner)) + $this->_owner = $this->_dms->getUser($this->_ownerID); + return $this->_owner; + } /* }}} */ + + /** + * Set the owner + * + * @param object new owner of the folder + * @return boolean true if successful otherwise false + */ + function setOwner($newOwner) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblFolders set owner = " . $newOwner->getID() . " WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_ownerID = $newOwner->getID(); + $this->_owner = $newOwner; + return true; + } /* }}} */ + + function getDefaultAccess() { /* {{{ */ + if ($this->inheritsAccess()) { + $res = $this->getParent(); + if (!$res) return false; + return $this->_parent->getDefaultAccess(); + } + + return $this->_defaultAccess; + } /* }}} */ + + /** + * Set default access mode + * + * This method sets the default access mode and also removes all notifiers which + * will not have read access anymore. + * + * @param integer $mode access mode + * @param boolean $noclean set to true if notifier list shall not be clean up + */ + function setDefaultAccess($mode, $noclean=false) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblFolders set defaultAccess = " . (int) $mode . " WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_defaultAccess = $mode; + + if(!$noclean) + self::cleanNotifyList(); + + return true; + } /* }}} */ + + function inheritsAccess() { return $this->_inheritAccess; } + + /** + * Set inherited access mode + * Setting inherited access mode will set or unset the internal flag which + * controls if the access mode is inherited from the parent folder or not. + * It will not modify the + * access control list for the current object. It will remove all + * notifications of users which do not even have read access anymore + * after setting or unsetting inherited access. + * + * @param boolean $inheritAccess set to true for setting and false for + * unsetting inherited access mode + * @param boolean $noclean set to true if notifier list shall not be clean up + * @return boolean true if operation was successful otherwise false + */ + function setInheritAccess($inheritAccess, $noclean=false) { /* {{{ */ + $db = $this->_dms->getDB(); + + $inheritAccess = ($inheritAccess) ? "1" : "0"; + + $queryStr = "UPDATE tblFolders SET inheritAccess = " . (int) $inheritAccess . " WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_inheritAccess = $inheritAccess; + + if(!$noclean) + self::cleanNotifyList(); + + return true; + } /* }}} */ + + function getSequence() { return $this->_sequence; } + + function setSequence($seq) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "UPDATE tblFolders SET sequence = " . $seq . " WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) + return false; + + $this->_sequence = $seq; + return true; + } /* }}} */ + + /** + * Check if folder has subfolders + * This function just checks if a folder has subfolders disregarding + * any access rights. + * + * @return int number of subfolders or false in case of an error + */ + function hasSubFolders() { /* {{{ */ + $db = $this->_dms->getDB(); + if (isset($this->_subFolders)) { + return count($this->subFolders); + } + $queryStr = "SELECT count(*) as c FROM tblFolders WHERE parent = " . $this->_id; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + return $resArr[0]['c']; + } /* }}} */ + + /** + * Returns a list of subfolders + * This function does not check for access rights. Use + * {@link SeedDMS_Core_DMS::filterAccess} for checking each folder against + * the currently logged in user and the access rights. + * + * @param string $orderby if set to 'n' the list is ordered by name, otherwise + * it will be ordered by sequence + * @param string $dir direction of sorting (asc or desc) + * @return array list of folder objects or false in case of an error + */ + function getSubFolders($orderby="", $dir="asc") { /* {{{ */ + $db = $this->_dms->getDB(); + + 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($dir == 'desc') + $queryStr .= " DESC"; + + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + $this->_subFolders = array(); + for ($i = 0; $i < count($resArr); $i++) + $this->_subFolders[$i] = $this->_dms->getFolder($resArr[$i]["id"]); + } + + return $this->_subFolders; + } /* }}} */ + + /** + * Add a new subfolder + * + * @param string $name name of folder + * @param string $comment comment of folder + * @param object $owner owner of folder + * @param integer $sequence position of folder in list of sub folders. + * @param array $attributes list of document attributes. The element key + * must be the id of the attribute definition. + * @return object object of type SeedDMS_Core_Folder or false in case of + * an error. + */ + function addSubFolder($name, $comment, $owner, $sequence, $attributes=array()) { /* {{{ */ + $db = $this->_dms->getDB(); + + // Set the folderList of the folder + $pathPrefix=""; + $path = $this->getPath(); + foreach ($path as $f) { + $pathPrefix .= ":".$f->getID(); + } + if (strlen($pathPrefix)>1) { + $pathPrefix .= ":"; + } + + $db->startTransaction(); + + //inheritAccess = true, defaultAccess = M_READ + $queryStr = "INSERT INTO tblFolders (name, parent, folderList, comment, date, owner, inheritAccess, defaultAccess, sequence) ". + "VALUES (".$db->qstr($name).", ".$this->_id.", ".$db->qstr($pathPrefix).", ".$db->qstr($comment).", ".$db->getCurrentTimestamp().", ".$owner->getID().", 1, ".M_READ.", ". $sequence.")"; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + $newFolder = $this->_dms->getFolder($db->getInsertID()); + unset($this->_subFolders); + + if($attributes) { + foreach($attributes as $attrdefid=>$attribute) { + if($attribute) + if(!$newFolder->setAttributeValue($this->_dms->getAttributeDefinition($attrdefid), $attribute)) { + $db->rollbackTransaction(); + return false; + } + } + } + + $db->commitTransaction(); + + /* Check if 'onPostAddSubFolder' callback is set */ + if(isset($this->_dms->callbacks['onPostAddSubFolder'])) { + foreach($this->_dms->callbacks['onPostAddSubFolder'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $newFolder)) { + } + } + } + + return $newFolder; + } /* }}} */ + + /** + * Returns an array of all parents, grand parent, etc. up to root folder. + * The folder itself is the last element of the array. + * + * @return array Array of parents + */ + function getPath() { /* {{{ */ + if (!isset($this->_parentID) || ($this->_parentID == "") || ($this->_parentID == 0) || ($this->_id == $this->_dms->rootFolderID)) { + return array($this); + } + else { + $res = $this->getParent(); + if (!$res) return false; + + $path = $this->_parent->getPath(); + if (!$path) return false; + + array_push($path, $this); + return $path; + } + } /* }}} */ + + /** + * Returns a file system path + * + * This path contains spaces around the slashes for better readability. + * Run str_replace(' / ', '/', $path) on it to get a valid unix + * file system path. + * + * @return string path separated with ' / ' + */ + function getFolderPathPlain() { /* {{{ */ + $path=""; + $folderPath = $this->getPath(); + for ($i = 0; $i < count($folderPath); $i++) { + $path .= $folderPath[$i]->getName(); + if ($i +1 < count($folderPath)) + $path .= " / "; + } + return $path; + } /* }}} */ + + /** + * Check, if this folder is a subfolder of a given folder + * + * @param object $folder parent folder + * @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 + return false; + } /* }}} */ + + /** + * Check if folder has documents + * This function just checks if a folder has documents diregarding + * any access rights. + * + * @return int number of documents or false in case of an error + */ + function hasDocuments() { /* {{{ */ + $db = $this->_dms->getDB(); + if (isset($this->_documents)) { + return count($this->documents); + } + $queryStr = "SELECT count(*) as c FROM tblDocuments WHERE folder = " . $this->_id; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + return $resArr[0]['c']; + } /* }}} */ + + /** + * Check if folder has document with given name + * + * @return boolean true if document exists, false if not or in case + * of an error + */ + function hasDocumentByName($name) { /* {{{ */ + $db = $this->_dms->getDB(); + if (isset($this->_documents)) { + return count($this->documents); + } + $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) + return false; + + return ($resArr[0]['c'] > 0); + } /* }}} */ + + /** + * Get all documents of the folder + * This function does not check for access rights. Use + * {@link SeedDMS_Core_DMS::filterAccess} for checking each document against + * the currently logged in user and the access rights. + * + * @param string $orderby if set to 'n' the list is ordered by name, otherwise + * it will be ordered by sequence + * @param string $dir direction of sorting (asc or desc) + * @return array list of documents or false in case of an error + */ + function getDocuments($orderby="", $dir="asc") { /* {{{ */ + $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"; + if($dir == 'desc') + $queryStr .= " DESC"; + + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + $this->_documents = array(); + 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"])); + } + } + return $this->_documents; + } /* }}} */ + + /** + * Count all documents and subfolders of the folder + * + * This function also counts documents and folders of subfolders, so + * basically it works like recursively counting children. + * + * This function checks for access rights up the given limit. If more + * documents or folders are found, the returned value will be the number + * of objects available and the precise flag in the return array will be + * set to false. This number should not be revelead to the + * user, because it allows to gain information about the existens of + * objects without access right. + * Setting the parameter $limit to 0 will turn off access right checking + * which is reasonable if the $user is an administrator. + * + * @param string $orderby if set to 'n' the list is ordered by name, otherwise + * it will be ordered by sequence + * @param integer $limit maximum number of folders and documents that will + * be precisly counted by taken the access rights into account + * @return array array with four elements 'document_count', 'folder_count' + * 'document_precise', 'folder_precise' holding + * the counted number and a flag if the number is precise. + */ + function countChildren($user, $limit=10000) { /* {{{ */ + $db = $this->_dms->getDB(); + + $pathPrefix=""; + $path = $this->getPath(); + foreach ($path as $f) { + $pathPrefix .= ":".$f->getID(); + } + if (strlen($pathPrefix)>1) { + $pathPrefix .= ":"; + } + + $queryStr = "SELECT id FROM tblFolders WHERE folderList like '".$pathPrefix. "%'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + $result = array(); + + $folders = array(); + $folderids = array($this->_id); + $cfolders = count($resArr); + if($cfolders < $limit) { + foreach ($resArr as $row) { + $folder = $this->_dms->getFolder($row["id"]); + if ($folder->getAccessMode($user) >= M_READ) { + array_push($folders, $folder); + array_push($folderids, $row['id']); + } + } + $result['folder_count'] = count($folders); + $result['folder_precise'] = true; + } else { + foreach ($resArr as $row) { + array_push($folderids, $row['id']); + } + $result['folder_count'] = $cfolders; + $result['folder_precise'] = false; + } + + $documents = array(); + if($folderids) { + $queryStr = "SELECT id FROM tblDocuments WHERE folder in (".implode(',', $folderids). ")"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + $cdocs = count($resArr); + if($cdocs < $limit) { + foreach ($resArr as $row) { + $document = $this->_dms->getDocument($row["id"]); + if ($document->getAccessMode($user) >= M_READ) + array_push($documents, $document); + } + $result['document_count'] = count($documents); + $result['document_precise'] = true; + } else { + $result['document_count'] = $cdocs; + $result['document_precise'] = false; + } + } + + return $result; + } /* }}} */ + + // $comment will be used for both document and version leaving empty the version_comment + /** + * Add a new document to the folder + * This function will add a new document and its content from a given file. + * It does not check for access rights on the folder. The new documents + * default access right is read only and the access right is inherited. + * + * @param string $name name of new document + * @param string $comment comment of new document + * @param integer $expires expiration date as a unix timestamp or 0 for no + * expiration date + * @param object $owner owner of the new document + * @param string $keywords keywords of new document + * @param array $categories list of category ids + * @param string $tmpFile the path of the file containing the content + * @param string $orgFileName the original file name + * @param string $fileType usually the extension of the filename + * @param string $mimeType mime type of the content + * @param float $sequence position of new document within the folder + * @param array $reviewers list of users who must review this document + * @param array $approvers list of users who must approve this document + * @param string $reqversion version number of the content + * @param string $version_comment comment of the content. If left empty + * the $comment will be used. + * @param array $attributes list of document attributes. The element key + * must be the id of the attribute definition. + * @param array $version_attributes list of document version attributes. + * The element key must be the id of the attribute definition. + * @param object $workflow + * @param integer $initstate initial document state (only S_RELEASED and + * S_DRAFT are allowed) + * @return array/boolean false in case of error, otherwise an array + * containing two elements. The first one is the new document, the + * second one is the result set returned when inserting the content. + */ + function addDocument($name, $comment, $expires, $owner, $keywords, $categories, $tmpFile, $orgFileName, $fileType, $mimeType, $sequence, $reviewers=array(), $approvers=array(),$reqversion=0,$version_comment="", $attributes=array(), $version_attributes=array(), $workflow=null, $initstate=S_RELEASED) { /* {{{ */ + $db = $this->_dms->getDB(); + + $expires = (!$expires) ? 0 : $expires; + + // Must also ensure that the document has a valid folderList. + $pathPrefix=""; + $path = $this->getPath(); + foreach ($path as $f) { + $pathPrefix .= ":".$f->getID(); + } + if (strlen($pathPrefix)>1) { + $pathPrefix .= ":"; + } + + $db->startTransaction(); + + $queryStr = "INSERT INTO tblDocuments (name, comment, date, expires, owner, folder, folderList, inheritAccess, defaultAccess, locked, keywords, sequence) VALUES ". + "(".$db->qstr($name).", ".$db->qstr($comment).", ".$db->getCurrentTimestamp().", ".(int) $expires.", ".$owner->getID().", ".$this->_id.",".$db->qstr($pathPrefix).", 1, ".M_READ.", -1, ".$db->qstr($keywords).", " . $sequence . ")"; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + + $document = $this->_dms->getDocument($db->getInsertID()); + +// if ($version_comment!="") + $res = $document->addContent($version_comment, $owner, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers, $approvers, $reqversion, $version_attributes, $workflow, $initstate); +// else $res = $document->addContent($comment, $owner, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers, $approvers,$reqversion, $version_attributes, $workflow); + + if (is_bool($res) && !$res) { + $db->rollbackTransaction(); + return false; + } + + if($categories) { + $document->setCategories($categories); + } + + if($attributes) { + foreach($attributes as $attrdefid=>$attribute) { + /* $attribute can be a string or an array */ + if($attribute) + if(!$document->setAttributeValue($this->_dms->getAttributeDefinition($attrdefid), $attribute)) { + $document->remove(); + $db->rollbackTransaction(); + return false; + } + } + } + + $db->commitTransaction(); + + /* Check if 'onPostAddDocument' callback is set */ + if(isset($this->_dms->callbacks['onPostAddDocument'])) { + foreach($this->_dms->callbacks['onPostAddDocument'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $document)) { + } + } + } + + return array($document, $res); + } /* }}} */ + + /** + * Remove a single folder + * + * Removes just a single folder, but not its subfolders or documents + * This function will fail if the folder has subfolders or documents + * because of referencial integrity errors. + * + * @return boolean true on success, false in case of an error + */ + protected function removeFromDatabase() { /* {{{ */ + $db = $this->_dms->getDB(); + + /* Check if 'onPreRemoveFolder' callback is set */ + if(isset($this->_dms->callbacks['onPreRemoveFolder'])) { + foreach($this->_dms->callbacks['onPreRemoveFolder'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $this)) { + return false; + } + } + } + + $db->startTransaction(); + // unset homefolder as it will no longer exist + $queryStr = "UPDATE tblUsers SET homefolder=NULL WHERE homefolder = " . $this->_id; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + + // Remove database entries + $queryStr = "DELETE FROM tblFolders WHERE id = " . $this->_id; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + $queryStr = "DELETE FROM tblFolderAttributes WHERE folder = " . $this->_id; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + $queryStr = "DELETE FROM tblACLs WHERE target = ". $this->_id. " AND targetType = " . T_FOLDER; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + + $queryStr = "DELETE FROM tblNotify WHERE target = ". $this->_id. " AND targetType = " . T_FOLDER; + if (!$db->getResult($queryStr)) { + $db->rollbackTransaction(); + return false; + } + $db->commitTransaction(); + + /* Check if 'onPostRemoveFolder' callback is set */ + if(isset($this->_dms->callbacks['onPostRemoveFolder'])) { + foreach($this->_dms->callbacks['onPostRemoveFolder'] as $callback) { + if(!call_user_func($callback[0], $callback[1], $this->_id)) { + } + } + } + + return true; + } /* }}} */ + + /** + * Remove recursively a folder + * + * Removes a folder, all its subfolders and documents + * + * @return boolean true on success, false in case of an error + */ + function remove() { /* {{{ */ + $db = $this->_dms->getDB(); + + // Do not delete the root folder. + if ($this->_id == $this->_dms->rootFolderID || !isset($this->_parentID) || ($this->_parentID == null) || ($this->_parentID == "") || ($this->_parentID == 0)) { + return false; + } + + //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; + } + } + + return $this->removeFromDatabase(); + } /* }}} */ + + /** + * Returns a list of access privileges + * + * If the folder inherits the access privileges from the parent folder + * those will be returned. + * $mode and $op can be set to restrict the list of returned access + * privileges. If $mode is set to M_ANY no restriction will apply + * regardless of the value of $op. The returned array contains a list + * of {@link SeedDMS_Core_UserAccess} and + * {@link SeedDMS_Core_GroupAccess} objects. Even if the document + * has no access list the returned array contains the two elements + * 'users' and 'groups' which are than empty. The methode returns false + * if the function fails. + * + * @param integer $mode access mode (defaults to M_ANY) + * @param integer $op operation (defaults to O_EQ) + * @return array multi dimensional array or false in case of an error + */ + function getAccessList($mode = M_ANY, $op = O_EQ) { /* {{{ */ + $db = $this->_dms->getDB(); + + if ($this->inheritsAccess()) { + $res = $this->getParent(); + if (!$res) return false; + $pacl = $res->getAccessList($mode, $op); + return $pacl; + } else { + $pacl = array("groups" => array(), "users" => array()); + } + + if (!isset($this->_accessList[$mode])) { + if ($op!=O_GTEQ && $op!=O_LTEQ && $op!=O_EQ) { + return false; + } + $modeStr = ""; + if ($mode!=M_ANY) { + $modeStr = " AND mode".$op.(int)$mode; + } + $queryStr = "SELECT * FROM tblACLs WHERE targetType = ".T_FOLDER. + " AND target = " . $this->_id . $modeStr . " ORDER BY targetType"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + + $this->_accessList[$mode] = array("groups" => array(), "users" => array()); + foreach ($resArr as $row) { + if ($row["userID"] != -1) + array_push($this->_accessList[$mode]["users"], new SeedDMS_Core_UserAccess($this->_dms->getUser($row["userID"]), $row["mode"])); + else //if ($row["groupID"] != -1) + array_push($this->_accessList[$mode]["groups"], new SeedDMS_Core_GroupAccess($this->_dms->getGroup($row["groupID"]), $row["mode"])); + } + } + + return $this->_accessList[$mode]; + return SeedDMS_Core_DMS::mergeAccessLists($pacl, $this->_accessList[$mode]); + } /* }}} */ + + /** + * Delete all entries for this folder from the access control list + * + * @param boolean $noclean set to true if notifier list shall not be clean up + * @return boolean true if operation was successful otherwise false + */ + function clearAccessList($noclean=false) { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "DELETE FROM tblACLs WHERE targetType = " . T_FOLDER . " AND target = " . $this->_id; + if (!$db->getResult($queryStr)) + return false; + + unset($this->_accessList); + + if(!$noclean) + self::cleanNotifyList(); + + return true; + } /* }}} */ + + /** + * Add access right to folder + * This function may change in the future. Instead of passing the a flag + * and a user/group id a user or group object will be expected. + * + * @param integer $mode access mode + * @param integer $userOrGroupID id of user or group + * @param integer $isUser set to 1 if $userOrGroupID is the id of a + * user + */ + function addAccess($mode, $userOrGroupID, $isUser) { /* {{{ */ + $db = $this->_dms->getDB(); + + $userOrGroup = ($isUser) ? "userID" : "groupID"; + + $queryStr = "INSERT INTO tblACLs (target, targetType, ".$userOrGroup.", mode) VALUES + (".$this->_id.", ".T_FOLDER.", " . (int) $userOrGroupID . ", " .(int) $mode. ")"; + if (!$db->getResult($queryStr)) + return false; + + unset($this->_accessList); + + // Update the notify list, if necessary. + if ($mode == M_NONE) { + $this->removeNotify($userOrGroupID, $isUser); + } + + return true; + } /* }}} */ + + /** + * Change access right of folder + * This function may change in the future. Instead of passing the a flag + * and a user/group id a user or group object will be expected. + * + * @param integer $newMode access mode + * @param integer $userOrGroupID id of user or group + * @param integer $isUser set to 1 if $userOrGroupID is the id of a + * user + */ + function changeAccess($newMode, $userOrGroupID, $isUser) { /* {{{ */ + $db = $this->_dms->getDB(); + + $userOrGroup = ($isUser) ? "userID" : "groupID"; + + $queryStr = "UPDATE tblACLs SET mode = " . (int) $newMode . " WHERE targetType = ".T_FOLDER." AND target = " . $this->_id . " AND " . $userOrGroup . " = " . (int) $userOrGroupID; + if (!$db->getResult($queryStr)) + return false; + + unset($this->_accessList); + + // Update the notify list, if necessary. + if ($newMode == M_NONE) { + $this->removeNotify($userOrGroupID, $isUser); + } + + return true; + } /* }}} */ + + function removeAccess($userOrGroupID, $isUser) { /* {{{ */ + $db = $this->_dms->getDB(); + + $userOrGroup = ($isUser) ? "userID" : "groupID"; + + $queryStr = "DELETE FROM tblACLs WHERE targetType = ".T_FOLDER." AND target = ".$this->_id." AND ".$userOrGroup." = " . (int) $userOrGroupID; + if (!$db->getResult($queryStr)) + return false; + + unset($this->_accessList); + + // Update the notify list, if necessary. + $mode = ($isUser ? $this->getAccessMode($this->_dms->getUser($userOrGroupID)) : $this->getGroupAccessMode($this->_dms->getGroup($userOrGroupID))); + if ($mode == M_NONE) { + $this->removeNotify($userOrGroupID, $isUser); + } + + return true; + } /* }}} */ + + /** + * Get the access mode of a user on the folder + * + * This function returns the access mode for a given user. An administrator + * and the owner of the folder has unrestricted access. A guest user has + * read only access or no access if access rights are further limited + * by access control lists. All other users have access rights according + * to the access control lists or the default access. This function will + * recursive check for access rights of parent folders if access rights + * are inherited. + * + * This function returns the access mode for a given user. An administrator + * and the owner of the folder has unrestricted access. A guest user has + * read only access or no access if access rights are further limited + * by access control lists. All other users have access rights according + * to the access control lists or the default access. This function will + * recursive check for access rights of parent folders if access rights + * are inherited. + * + * @param object $user user for which access shall be checked + * @return integer access mode + */ + function getAccessMode($user) { /* {{{ */ + if(!$user) + return M_NONE; + + /* Administrators have unrestricted access */ + if ($user->isAdmin()) return M_ALL; + + /* The owner of the document has unrestricted access */ + if ($user->getID() == $this->_ownerID) return M_ALL; + + /* Check ACLs */ + $accessList = $this->getAccessList(); + if (!$accessList) return false; + + foreach ($accessList["users"] as $userAccess) { + if ($userAccess->getUserID() == $user->getID()) { + $mode = $userAccess->getMode(); + if ($user->isGuest()) { + if ($mode >= M_READ) $mode = M_READ; + } + return $mode; + } + } + + /* Get the highest right defined by a group */ + if($accessList['groups']) { + $mode = 0; + foreach ($accessList["groups"] as $groupAccess) { + if ($user->isMemberOfGroup($groupAccess->getGroup())) { + if ($groupAccess->getMode() > $mode) + $mode = $groupAccess->getMode(); + } + } + if($mode) { + if ($user->isGuest()) { + if ($mode >= M_READ) $mode = M_READ; + } + return $mode; + } + } + + $mode = $this->getDefaultAccess(); + if ($user->isGuest()) { + if ($mode >= M_READ) $mode = M_READ; + } + return $mode; + } /* }}} */ + + /** + * Get the access mode for a group on the folder + * This function returns the access mode for a given group. The algorithmn + * applied to get the access mode is the same as describe at + * {@link getAccessMode} + * + * @param object $group group for which access shall be checked + * @return integer access mode + */ + function getGroupAccessMode($group) { /* {{{ */ + $highestPrivileged = M_NONE; + $foundInACL = false; + $accessList = $this->getAccessList(); + if (!$accessList) + return false; + + foreach ($accessList["groups"] as $groupAccess) { + if ($groupAccess->getGroupID() == $group->getID()) { + $foundInACL = true; + if ($groupAccess->getMode() > $highestPrivileged) + $highestPrivileged = $groupAccess->getMode(); + if ($highestPrivileged == M_ALL) /* no need to check further */ + return $highestPrivileged; + } + } + if ($foundInACL) + return $highestPrivileged; + + /* Take default access */ + return $this->getDefaultAccess(); + } /* }}} */ + + /** + * Get a list of all notification + * This function returns all users and groups that have registerd a + * notification for the folder + * + * @param integer $type type of notification (not yet used) + * @return array array with a the elements 'users' and 'groups' which + * contain a list of users and groups. + */ + function getNotifyList($type=0) { /* {{{ */ + if (empty($this->_notifyList)) { + $db = $this->_dms->getDB(); + + $queryStr ="SELECT * FROM tblNotify WHERE targetType = " . T_FOLDER . " AND target = " . $this->_id; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + $this->_notifyList = array("groups" => array(), "users" => array()); + foreach ($resArr as $row) + { + if ($row["userID"] != -1) + array_push($this->_notifyList["users"], $this->_dms->getUser($row["userID"]) ); + else //if ($row["groupID"] != -1) + array_push($this->_notifyList["groups"], $this->_dms->getGroup($row["groupID"]) ); + } + } + return $this->_notifyList; + } /* }}} */ + + /** + * Make sure only users/groups with read access are in the notify list + * + */ + function cleanNotifyList() { /* {{{ */ + // If any of the notification subscribers no longer have read access, + // remove their subscription. + if (empty($this->_notifyList)) + $this->getNotifyList(); + + /* Make a copy of both notifier lists because removeNotify will empty + * $this->_notifyList and the second foreach will not work anymore. + */ + $nusers = $this->_notifyList["users"]; + $ngroups = $this->_notifyList["groups"]; + foreach ($nusers as $u) { + if ($this->getAccessMode($u) < M_READ) { + $this->removeNotify($u->getID(), true); + } + } + foreach ($ngroups as $g) { + if ($this->getGroupAccessMode($g) < M_READ) { + $this->removeNotify($g->getID(), false); + } + } + } /* }}} */ + + /* + * Add a user/group to the notification list + * This function does not check if the currently logged in user + * is allowed to add a notification. This must be checked by the calling + * application. + * + * @param integer $userOrGroupID + * @param boolean $isUser true if $userOrGroupID is a user id otherwise false + * @return integer error code + * -1: Invalid User/Group ID. + * -2: Target User / Group does not have read access. + * -3: User is already subscribed. + * -4: Database / internal error. + * 0: Update successful. + */ + function addNotify($userOrGroupID, $isUser) { /* {{{ */ + $db = $this->_dms->getDB(); + + $userOrGroup = ($isUser) ? "userID" : "groupID"; + + /* Verify that user / group exists */ + $obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID)); + if (!is_object($obj)) { + return -1; + } + + /* Verify that the requesting user has permission to add the target to + * the notification system. + */ + /* + * The calling application should enforce the policy on who is allowed + * to add someone to the notification system. If is shall remain here + * the currently logged in user should be passed to this function + * + GLOBAL $user; + if ($user->isGuest()) { + return -2; + } + if (!$user->isAdmin()) { + if ($isUser) { + if ($user->getID() != $obj->getID()) { + return -2; + } + } + else { + if (!$obj->isMember($user)) { + return -2; + } + } + } + */ + + // + // Verify that user / group has read access to the document. + // + if ($isUser) { + // Users are straightforward to check. + if ($this->getAccessMode($obj) < M_READ) { + return -2; + } + } + else { + // FIXME: Why not check the access list first and if this returns + // not result, then use the default access? + // Groups are a little more complex. + if ($this->getDefaultAccess() >= M_READ) { + // If the default access is at least READ-ONLY, then just make sure + // that the current group has not been explicitly excluded. + $acl = $this->getAccessList(M_NONE, O_EQ); + $found = false; + foreach ($acl["groups"] as $group) { + if ($group->getGroupID() == $userOrGroupID) { + $found = true; + break; + } + } + if ($found) { + return -2; + } + } + else { + // The default access is restricted. Make sure that the group has + // been explicitly allocated access to the document. + $acl = $this->getAccessList(M_READ, O_GTEQ); + if (is_bool($acl)) { + return -4; + } + $found = false; + foreach ($acl["groups"] as $group) { + if ($group->getGroupID() == $userOrGroupID) { + $found = true; + break; + } + } + if (!$found) { + return -2; + } + } + } + // + // Check to see if user/group is already on the list. + // + $queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ". + "AND `tblNotify`.`targetType` = '".T_FOLDER."' ". + "AND `tblNotify`.`".$userOrGroup."` = '". (int) $userOrGroupID."'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr)) { + return -4; + } + if (count($resArr)>0) { + return -3; + } + + $queryStr = "INSERT INTO tblNotify (target, targetType, " . $userOrGroup . ") VALUES (" . $this->_id . ", " . T_FOLDER . ", " . (int) $userOrGroupID . ")"; + if (!$db->getResult($queryStr)) + return -4; + + unset($this->_notifyList); + return 0; + } /* }}} */ + + /* + * Removes notify for a user or group to folder + * This function does not check if the currently logged in user + * is allowed to remove a notification. This must be checked by the calling + * application. + * + * @param integer $userOrGroupID + * @param boolean $isUser true if $userOrGroupID is a user id otherwise false + * @param $type type of notification (0 will delete all) Not used yet! + * @return integer error code + * -1: Invalid User/Group ID. + * -3: User is not subscribed. + * -4: Database / internal error. + * 0: Update successful. + */ + function removeNotify($userOrGroupID, $isUser, $type=0) { /* {{{ */ + $db = $this->_dms->getDB(); + + /* Verify that user / group exists. */ + $obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID)); + if (!is_object($obj)) { + return -1; + } + + $userOrGroup = ($isUser) ? "userID" : "groupID"; + + /* Verify that the requesting user has permission to add the target to + * the notification system. + */ + /* + * The calling application should enforce the policy on who is allowed + * to add someone to the notification system. If is shall remain here + * the currently logged in user should be passed to this function + * + GLOBAL $user; + if ($user->isGuest()) { + return -2; + } + if (!$user->isAdmin()) { + if ($isUser) { + if ($user->getID() != $obj->getID()) { + return -2; + } + } + else { + if (!$obj->isMember($user)) { + return -2; + } + } + } + */ + + // + // Check to see if the target is in the database. + // + $queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ". + "AND `tblNotify`.`targetType` = '".T_FOLDER."' ". + "AND `tblNotify`.`".$userOrGroup."` = '". (int) $userOrGroupID."'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr)) { + return -4; + } + if (count($resArr)==0) { + return -3; + } + + $queryStr = "DELETE FROM tblNotify WHERE target = " . $this->_id . " AND targetType = " . T_FOLDER . " AND " . $userOrGroup . " = " . (int) $userOrGroupID; + /* If type is given then delete only those notifications */ + if($type) + $queryStr .= " AND `type` = ".(int) $type; + if (!$db->getResult($queryStr)) + return -4; + + unset($this->_notifyList); + return 0; + } /* }}} */ + + /** + * Get List of users and groups which have read access on the document + * + * This function is deprecated. Use + * {@see SeedDMS_Core_Folder::getReadAccessList()} instead. + */ + function getApproversList() { /* {{{ */ + return $this->getReadAccessList(0, 0); + } /* }}} */ + + /** + * Returns a list of groups and users with read access on the folder + * The list will not include any guest users, + * administrators and the owner of the folder unless $listadmin resp. + * $listowner is set to true. + * + * @param boolean $listadmin if set to true any admin will be listed too + * @param boolean $listowner if set to true the owner will be listed too + * + * @return array list of users and groups + */ + function getReadAccessList($listadmin=0, $listowner=0) { /* {{{ */ + $db = $this->_dms->getDB(); + + if (!isset($this->_readAccessList)) { + $this->_readAccessList = array("groups" => array(), "users" => array()); + $userIDs = ""; + $groupIDs = ""; + $defAccess = $this->getDefaultAccess(); + + /* Check if the default access is < read access or >= read access. + * If default access is less than read access, then create a list + * of users and groups with read access. + * If default access is equal or greater then read access, then + * create a list of users and groups without read access. + */ + if ($defAccessgetAccessList(M_READ, O_GTEQ); + } + else { + // Get the list of all users and groups that DO NOT have read access + // to the folder. + $tmpList = $this->getAccessList(M_NONE, O_LTEQ); + } + foreach ($tmpList["groups"] as $groupAccess) { + $groupIDs .= (strlen($groupIDs)==0 ? "" : ", ") . $groupAccess->getGroupID(); + } + foreach ($tmpList["users"] as $userAccess) { + $user = $userAccess->getUser(); + if (!$listadmin && $user->isAdmin()) continue; + if (!$listowner && $user->getID() == $this->_ownerID) continue; + if ($user->isGuest()) continue; + $userIDs .= (strlen($userIDs)==0 ? "" : ", ") . $userAccess->getUserID(); + } + + // Construct a query against the users table to identify those users + // that have read access to this folder, either directly through an + // ACL entry, by virtue of ownership or by having administrative rights + // on the database. + $queryStr=""; + /* If default access is less then read, $userIDs and $groupIDs contains + * a list of user with read access + */ + if ($defAccess < M_READ) { + if (strlen($groupIDs)>0) { + $queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ". + "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ". + "WHERE `tblGroupMembers`.`groupID` IN (". $groupIDs .") ". + "AND `tblUsers`.`role` != ".SeedDMS_Core_User::role_guest." UNION "; + } + $queryStr .= + "SELECT `tblUsers`.* FROM `tblUsers` ". + "WHERE (`tblUsers`.`role` != ".SeedDMS_Core_User::role_guest.") ". + "AND ((`tblUsers`.`id` = ". $this->_ownerID . ") ". + "OR (`tblUsers`.`role` = ".SeedDMS_Core_User::role_admin.")". + (strlen($userIDs) == 0 ? "" : " OR (`tblUsers`.`id` IN (". $userIDs ."))"). + ") ORDER BY `login`"; + } + /* If default access is equal or greate then read, $userIDs and + * $groupIDs contains a list of user without read access + */ + else { + if (strlen($groupIDs)>0) { + $queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ". + "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ". + "WHERE `tblGroupMembers`.`groupID` NOT IN (". $groupIDs .")". + "AND `tblUsers`.`role` != ".SeedDMS_Core_User::role_guest." ". + (strlen($userIDs) == 0 ? "" : " AND (`tblUsers`.`id` NOT IN (". $userIDs ."))")." UNION "; + } + $queryStr .= + "SELECT `tblUsers`.* FROM `tblUsers` ". + "WHERE (`tblUsers`.`id` = ". $this->_ownerID . ") ". + "OR (`tblUsers`.`role` = ".SeedDMS_Core_User::role_admin.") ". + "UNION ". + "SELECT `tblUsers`.* FROM `tblUsers` ". + "WHERE `tblUsers`.`role` != ".SeedDMS_Core_User::role_guest." ". + (strlen($userIDs) == 0 ? "" : " AND (`tblUsers`.`id` NOT IN (". $userIDs ."))"). + " ORDER BY `login`"; + } + $resArr = $db->getResultArray($queryStr); + if (!is_bool($resArr)) { + foreach ($resArr as $row) { + $user = $this->_dms->getUser($row['id']); + if (!$listadmin && $user->isAdmin()) continue; + if (!$listowner && $user->getID() == $this->_ownerID) continue; + $this->_readAccessList["users"][] = $user; + } + } + + // Assemble the list of groups that have read access to the folder. + $queryStr=""; + if ($defAccess < M_READ) { + if (strlen($groupIDs)>0) { + $queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ". + "WHERE `tblGroups`.`id` IN (". $groupIDs .")"; + } + } + else { + if (strlen($groupIDs)>0) { + $queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ". + "WHERE `tblGroups`.`id` NOT IN (". $groupIDs .")"; + } + else { + $queryStr = "SELECT `tblGroups`.* FROM `tblGroups`"; + } + } + if (strlen($queryStr)>0) { + $resArr = $db->getResultArray($queryStr); + if (!is_bool($resArr)) { + foreach ($resArr as $row) { + $group = $this->_dms->getGroup($row["id"]); + $this->_readAccessList["groups"][] = $group; + } + } + } + } + return $this->_readAccessList; + } /* }}} */ + + /** + * Get the internally used folderList which stores the ids of folders from + * the root folder to the parent folder. + * + * @return string column separated list of folder ids + */ + function getFolderList() { /* {{{ */ + $db = $this->_dms->getDB(); + + $queryStr = "SELECT folderList FROM tblFolders where id = ".$this->_id; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && !$resArr) + return false; + return $resArr[0]['folderList']; + } /* }}} */ + + /** + * Checks the internal data of the folder and repairs it. + * Currently, this function only repairs an incorrect folderList + * + * @return boolean true on success, otherwise false + */ + function repair() { /* {{{ */ + $db = $this->_dms->getDB(); + + $curfolderlist = $this->getFolderList(); + + // calculate the folderList of the folder + $parent = $this->getParent(); + $pathPrefix=""; + $path = $parent->getPath(); + foreach ($path as $f) { + $pathPrefix .= ":".$f->getID(); + } + if (strlen($pathPrefix)>1) { + $pathPrefix .= ":"; + } + if($curfolderlist != $pathPrefix) { + $queryStr = "UPDATE tblFolders SET folderList='".$pathPrefix."' WHERE id = ". $this->_id; + $res = $db->getResult($queryStr); + if (!$res) + return false; + } + return true; + } /* }}} */ + + + /** + * Get a list of all assigned attribute defintion groups + * + * @return array array with a the elements 'users' and 'groups' which + * contain a list of users and groups. + */ + function getAttributeDefintionGroupList() { /* {{{ */ + if (empty($this->_attrdefgrpList)) { + $db = $this->_dms->getDB(); + + $queryStr ="SELECT * FROM tblFolderAttributeDefinitionGroup WHERE folder = " . $this->_id . " ORDER BY `sequence`"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + $this->_attrdefgrpList = array(); + foreach ($resArr as $row) { + array_push($this->_attrdefgrpList, array('group'=>$this->_dms->getAttributeDefinitionGroup($row["attrgrp"]), 'sequence'=>$row['sequence'])); + } + } + return $this->_attrdefgrpList; + } /* }}} */ + + /* + * Add an attribute definition group to the folder + * + * @param object $attrdefgroup + * @param float $seq + * @return integer error code + * -1: Invalid attrdefgroup. + * -3: Attribute Definition Group is already added. + * -4: Database / internal error. + * 0: Update successful. + */ + function addAttributeDefinitionGroup($attrdefgroup, $seq=false) { /* {{{ */ + $db = $this->_dms->getDB(); + + /* Verify that attribute definition group exists */ + if (!is_object($attrdefgroup)) { + return -1; + } + + // Check to see if attribute definition group is already on the list. + $queryStr = "SELECT * FROM `tblFolderAttributeDefinitionGroup` WHERE `folder` = '".$this->_id."' ". + "AND `attrgrp` = '". (int) $attrdefgroup->getID()."'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr)) { + return -4; + } + if (count($resArr)>0) { + return -3; + } + + if(!$seq || !is_numeric($seq)) { + $queryStr = "SELECT MAX(`sequence`) as m FROM `tblFolderAttributeDefinitionGroup` ". + "WHERE `folder` = '". $this->_id."'"; + $resArr = $db->getResultArray($queryStr); + if (is_bool($resArr) && $resArr == false) + return false; + + if(!$resArr) + $seq = 10.0; + else + $seq = $resArr[0]['m'] + 10.0; + } + + $queryStr = "INSERT INTO tblFolderAttributeDefinitionGroup (folder, attrgrp, sequence) VALUES (" . $this->_id . ", " . (int) $attrdefgroup->getID() . ", " . $seq . ")"; + if (!$db->getResult($queryStr)) + return -4; + + unset($this->_attrdefgrpList); + return 0; + } /* }}} */ + +} + +?> diff --git a/op/op.AttributeGroupMgr.php b/op/op.AttributeGroupMgr.php new file mode 100644 index 000000000..0c8eebb17 --- /dev/null +++ b/op/op.AttributeGroupMgr.php @@ -0,0 +1,275 @@ +isAdmin()) { + UI::exitError(getMLText("admin_tools"),getMLText("access_denied")); +} + +if (isset($_POST["action"])) $action = $_POST["action"]; +else $action = null; + +// Create new group -------------------------------------------------------- +if ($action == "addgroup") { + + /* Check if the form data comes for a trusted request */ + if(!checkFormKey('addgroup')) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_request_token")); + } + + $name = $_POST["name"]; + $comment = $_POST["comment"]; + + if (is_object($dms->getAttributeDefinitionGroupByName($name))) { + UI::exitError(getMLText("admin_tools"),getMLText("group_exists")); + } + + $newGroup = $dms->addAttributeDefinitionGroup($name, $comment); + if (!$newGroup) { + UI::exitError(getMLText("admin_tools"),getMLText("error_occured")); + } + + $groupid=$newGroup->getID(); + + $session->setSplashMsg(array('type'=>'success', 'msg'=>getMLText('splash_add_group'))); + + add_log_line("&action=addgroup&name=".$name); +} + +// Delete group ------------------------------------------------------------- +else if ($action == "removegroup") { + + /* Check if the form data comes for a trusted request */ + if(!checkFormKey('removegroup')) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_request_token")); + } + + if (!isset($_POST["attrdefgroupid"]) || !is_numeric($_POST["attrdefgroupid"]) || intval($_POST["attrdefgroupid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + $group = $dms->getAttributeDefinitionGroup($_POST["attrdefgroupid"]); + if (!is_object($group)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + if (!$group->remove($user)) { + UI::exitError(getMLText("admin_tools"),getMLText("error_occured")); + } + + $groupid = ''; + + $session->setSplashMsg(array('type'=>'success', 'msg'=>getMLText('splash_rm_group'))); + + add_log_line("?attrdefgroupid=".$_POST["attrdefgroupid"]."&action=removegroup"); +} + +// Modifiy group ------------------------------------------------------------ +else if ($action == "editgroup") { + + /* Check if the form data comes for a trusted request */ + if(!checkFormKey('editgroup')) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_request_token")); + } + + if (!isset($_POST["attrdefgroupid"]) || !is_numeric($_POST["attrdefgroupid"]) || intval($_POST["attrdefgroupid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + $groupid=$_POST["attrdefgroupid"]; + $group = $dms->getAttributeDefinitionGroup($groupid); + + if (!is_object($group)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + $name = $_POST["name"]; + $comment = $_POST["comment"]; + + if ($group->getName() != $name) + $group->setName($name); + if ($group->getComment() != $comment) + $group->setComment($comment); + + $session->setSplashMsg(array('type'=>'success', 'msg'=>getMLText('splash_edit_group'))); + + add_log_line("?attrdefgroupid=".$_POST["attrdefgroupid"]."&action=editgroup"); +} + +// Add user to group -------------------------------------------------------- +else if ($action == "addmember") { + + /* Check if the form data comes for a trusted request */ + if(!checkFormKey('addmember')) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_request_token")); + } + + if (!isset($_POST["attrdefgroupid"]) || !is_numeric($_POST["attrdefgroupid"]) || intval($_POST["attrdefgroupid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + $groupid=$_POST["attrdefgroupid"]; + $group = $dms->getAttributeDefinitionGroup($groupid); + + if (!is_object($group)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + if (!isset($_POST["attrdefid"]) || !is_numeric($_POST["attrdefid"]) || intval($_POST["attrdefid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $newMember = $dms->getAttributeDefinition($_POST["attrdefid"]); + if (!is_object($newMember)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $show = 0; + foreach($_POST['shows'] as $s) { + $show += $s; + } + + if (!$group->isMember($newMember)){ + $group->addAttributeDefinition($newMember, $show); + } + + $session->setSplashMsg(array('type'=>'success', 'msg'=>getMLText('splash_add_group_member'))); + + add_log_line("?attrdefgroupid=".$groupid."&attrdefid=".$_POST["attrdefid"]."&action=addmember"); +} + +// Remove attribute definition from group -------------------------------------------------- +else if ($action == "rmmember") { + + /* Check if the form data comes for a trusted request */ + if(!checkFormKey('rmmember')) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_request_token")); + } + + if (!isset($_POST["attrdefgroupid"]) || !is_numeric($_POST["attrdefgroupid"]) || intval($_POST["attrdefgroupid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + $groupid=$_POST["attrdefgroupid"]; + $group = $dms->getAttributeDefinitionGroup($groupid); + + if (!is_object($group)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + if (!isset($_POST["attrdefid"]) || !is_numeric($_POST["attrdefid"]) || intval($_POST["attrdefid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $oldMember = $dms->getAttributeDefinition($_POST["attrdefid"]); + if (!is_object($oldMember)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $group->removeAttributeDefinition($oldMember); + + $session->setSplashMsg(array('type'=>'success', 'msg'=>getMLText('splash_rm_group_member'))); + + add_log_line("?attrdefgroupid=".$groupid."&attrdefid=".$_POST["attrdefid"]."&action=rmmember"); +} + +// Set sequence of member of group -------------------------------------------------- +else if ($action == "setsequence") { + /* Check if the form data comes for a trusted request */ + if(!checkFormKey('setsequence')) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_request_token")); + } + + if (!isset($_POST["attrdefgroupid"]) || !is_numeric($_POST["attrdefgroupid"]) || intval($_POST["attrdefgroupid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + $groupid=$_POST["attrdefgroupid"]; + $group = $dms->getAttributeDefinitionGroup($groupid); + + if (!is_object($group)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + if (!isset($_POST["attrdefid"]) || !is_numeric($_POST["attrdefid"]) || intval($_POST["attrdefid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $member = $dms->getAttributeDefinition($_POST["attrdefid"]); + if (!is_object($member)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $group->setSequence($member, $_POST['sequence']); + + $session->setSplashMsg(array('type'=>'success', 'msg'=>getMLText('splash_set_group_sequence'))); + + add_log_line("?attrdefgroupid=".$groupid."&attrdefid=".$_POST["attrdefid"]."&action=setsequence"); +} + +// Set show of member of group -------------------------------------------------- +else if ($action == "setshow") { + /* Check if the form data comes for a trusted request */ + if(!checkFormKey('setshow')) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_request_token")); + } + + if (!isset($_POST["attrdefgroupid"]) || !is_numeric($_POST["attrdefgroupid"]) || intval($_POST["attrdefgroupid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + $groupid=$_POST["attrdefgroupid"]; + $group = $dms->getAttributeDefinitionGroup($groupid); + + if (!is_object($group)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_group_id")); + } + + if (!isset($_POST["attrdefid"]) || !is_numeric($_POST["attrdefid"]) || intval($_POST["attrdefid"])<1) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $member = $dms->getAttributeDefinition($_POST["attrdefid"]); + if (!is_object($member)) { + UI::exitError(getMLText("admin_tools"),getMLText("invalid_user_id")); + } + + $show = 0; + foreach($_POST['shows'] as $s) { + $show += $s; + } + $group->setShow($member, $show); + + $session->setSplashMsg(array('type'=>'success', 'msg'=>getMLText('splash_set_group_show'))); + + add_log_line("?attrdefgroupid=".$groupid."&attrdefid=".$_POST["attrdefid"]."&action=setshow"); +} + +header("Location:../out/out.AttributeGroupMgr.php?attrdefgroupid=".$groupid); + +?> diff --git a/op/op.FolderAttributeGroup.php b/op/op.FolderAttributeGroup.php new file mode 100644 index 000000000..9c9ab0cb5 --- /dev/null +++ b/op/op.FolderAttributeGroup.php @@ -0,0 +1,117 @@ + $folder->getName())),getMLText("invalid_request_token")); +} + +if (!isset($_POST["folderid"]) || !is_numeric($_POST["folderid"]) || intval($_POST["folderid"])<1) { + UI::exitError(getMLText("folder_title", array("foldername" => getMLText("invalid_folder_id"))),getMLText("invalid_folder_id")); +} + +$folderid = $_POST["folderid"]; +$folder = $dms->getFolder($folderid); + +if (!is_object($folder)) { + UI::exitError(getMLText("folder_title", array("foldername" => getMLText("invalid_folder_id"))),getMLText("invalid_folder_id")); +} + +if (!isset($_POST["action"]) || (strcasecmp($_POST["action"], "delattributegroup") && strcasecmp($_POST["action"], "addattributegroup"))) { + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("invalid_action")); +} +$action = $_POST["action"]; + +if (isset($_POST["groupid"]) && (!is_numeric($_POST["groupid"]) || $_POST["groupid"]<-1)) { + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("unknown_group")); +} +$groupid = isset($_POST["groupid"]) ? $_POST["groupid"] : -1; + +if (isset($_POST["groupid"])&&$_POST["groupid"]!=-1){ + $group=$dms->getAttributeDefinitionGroup($groupid); + if (!$user->isAdmin()) + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("access_denied")); +} + +$folderPathHTML = getFolderPathHTML($folder, true); + +if ($folder->getAccessMode($user) < M_READ) { + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("access_denied")); +} + +// Delete notification ------------------------------------------------------- +if ($action == "delattributegroup") { + + if ($groupid > 0) { + $res = $folder->removeAttributeDefinitionGroup($group); + $obj = $dms->getGroup($groupid); + } + switch ($res) { + case -1: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),isset($userid) ? getMLText("unknown_user") : getMLText("unknown_group")); + break; + case -2: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("access_denied")); + break; + case -3: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("already_subscribed")); + break; + case -4: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("internal_error")); + break; + case 0: + break; + } +} + +// Add notification ---------------------------------------------------------- +else if ($action == "addattributegroup") { + + if ($groupid != -1) { + $res = $folder->addAttributeDefinitionGroup($group, false); + switch ($res) { + case -1: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("unknown_group")); + break; + case -2: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("access_denied")); + break; + case -3: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("already_subscribed")); + break; + case -4: + UI::exitError(getMLText("folder_title", array("foldername" => $folder->getName())),getMLText("internal_error")); + break; + case 0: + break; + } + } +} + +header("Location:../out/out.FolderAttributeGroup.php?folderid=".$folderid); + +?> diff --git a/out/out.AttributeGroupMgr.php b/out/out.AttributeGroupMgr.php new file mode 100644 index 000000000..d9b5b807a --- /dev/null +++ b/out/out.AttributeGroupMgr.php @@ -0,0 +1,64 @@ +$dms, 'user'=>$user)); +$accessop = new SeedDMS_AccessOperation($dms, $user, $settings); +if (!$accessop->check_view_access($view, $_GET)) { + UI::exitError(getMLText("admin_tools"),getMLText("access_denied")); +} + +$attrdefs = $dms->getAllAttributeDefinitions(); +if (is_bool($attrdefs)) { + UI::exitError(getMLText("admin_tools"),getMLText("internal_error")); +} + +$attrdefgroups = $dms->getAllAttributeDefinitionGroups(); +if (is_bool($attrdefgroups)) { + UI::exitError(getMLText("admin_tools"),getMLText("internal_error")); +} + +if(isset($_GET['attrdefgroupid']) && $_GET['attrdefgroupid']) { + $selgroup = $dms->getAttributeDefinitionGroup($_GET['attrdefgroupid']); +} else { + $selgroup = null; +} + +if($view) { + $view->setParam('selattrdefgroup', $selgroup); + $view->setParam('attrdefgroups', $attrdefgroups); + $view->setParam('attrdefs', $attrdefs); + $view->setParam('strictformcheck', $settings->_strictFormCheck); + $view->setParam('cachedir', $settings->_cacheDir); + $view->setParam('previewWidthList', $settings->_previewWidthList); + $view->setParam('workflowmode', $settings->_workflowMode); + $view->setParam('timeout', $settings->_cmdTimeout); + $view->setParam('accessobject', $accessop); + $view($_GET); +} diff --git a/out/out.EditFolder.php b/out/out.EditFolder.php index 7e09f04f6..b5a693e46 100644 --- a/out/out.EditFolder.php +++ b/out/out.EditFolder.php @@ -50,10 +50,12 @@ if ($folder->getAccessMode($user) < M_READWRITE) { } $attrdefs = $dms->getAllAttributeDefinitions(array(SeedDMS_Core_AttributeDefinition::objtype_folder, SeedDMS_Core_AttributeDefinition::objtype_all)); +$attrdefgrps = $folder->getAttributeDefintionGroupList(); if($view) { $view->setParam('folder', $folder); $view->setParam('attrdefs', $attrdefs); + $view->setParam('attrdefgrps', $attrdefgrps); $view->setParam('strictformcheck', $settings->_strictFormCheck); $view->setParam('nofolderformfields', $settings->_noFolderFormFields); $view->setParam('rootfolderid', $settings->_rootFolderID); diff --git a/out/out.FolderAttributeGroup.php b/out/out.FolderAttributeGroup.php new file mode 100644 index 000000000..800b75c2e --- /dev/null +++ b/out/out.FolderAttributeGroup.php @@ -0,0 +1,58 @@ +$dms, 'user'=>$user)); +$accessop = new SeedDMS_AccessOperation($dms, $user, $settings); + +if (!isset($_GET["folderid"]) || !is_numeric($_GET["folderid"]) || intval($_GET["folderid"])<1) { + UI::exitError(getMLText("folder_title", array("foldername" => getMLText("invalid_folder_id"))),getMLText("invalid_folder_id")); +} +$folder = $dms->getFolder($_GET["folderid"]); + +if (!is_object($folder)) { + UI::exitError(getMLText("folder_title", array("foldername" => getMLText("invalid_folder_id"))),getMLText("invalid_folder_id")); +} + +if ($folder->getAccessMode($user) < M_READ) { + UI::exitError(getMLText("folder_title", array("foldername" => htmlspecialchars($folder->getName()))),getMLText("access_denied")); +} + +$allAttrGroups = $dms->getAllAttributeDefinitionGroups($settings->_sortUsersInList); + +if($view) { + $view->setParam('folder', $folder); + $view->setParam('allattrgrps', $allAttrGroups); + $view->setParam('strictformcheck', $settings->_strictFormCheck); + $view->setParam('accessobject', $accessop); + $view($_GET); + exit; +} + +?> diff --git a/views/bootstrap/class.AttributeGroupMgr.php b/views/bootstrap/class.AttributeGroupMgr.php new file mode 100644 index 000000000..adfbab55b --- /dev/null +++ b/views/bootstrap/class.AttributeGroupMgr.php @@ -0,0 +1,367 @@ + + * @copyright Copyright (C) 2002-2005 Markus Westphal, + * 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli, + * 2010-2012 Uwe Steinmann + * @version Release: @package_version@ + */ + +/** + * Include parent class + */ +require_once("class.Bootstrap.php"); + +/** + * Include class to preview documents + */ +require_once("SeedDMS/Preview.php"); + +/** + * Class which outputs the html page for AttributeGroupMgr view + * + * @category DMS + * @package SeedDMS + * @author Markus Westphal, Malcolm Cowe, Uwe Steinmann + * @copyright Copyright (C) 2002-2005 Markus Westphal, + * 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli, + * 2010-2012 Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_View_AttributeGroupMgr extends SeedDMS_Bootstrap_Style { + + function js() { /* {{{ */ + $selgroup = $this->params['selattrdefgroup']; + $strictformcheck = $this->params['strictformcheck']; + + header("Content-type: text/javascript"); +?> +function checkForm1() { + msg = new Array(); + + if($("#name").val() == "") msg.push(""); + + if($("#comment").val() == "") msg.push(""); + + if (msg != "") { + noty({ + text: msg.join('
'), + type: 'error', + dismissQueue: true, + layout: 'topRight', + theme: 'defaultTheme', + _timeout: 1500, + }); + return false; + } else + return true; +} + +function checkForm2() { + msg = ""; + + if($("#attrdefid").val() == -1) msg += "\n"; + + if (msg != "") { + noty({ + text: msg, + type: 'error', + dismissQueue: true, + layout: 'topRight', + theme: 'defaultTheme', + _timeout: 1500, + }); + return false; + } else + return true; + } + +$(document).ready( function() { + $('body').on('submit', '#form_1', function(ev){ + if(checkForm1()) + return; + ev.preventDefault(); + }); + + $('body').on('submit', '#form_2', function(ev){ + if(checkForm2()) + return; + ev.preventDefault(); + }); + + $( "#selector" ).change(function() { + $('div.ajax').trigger('update', {attrdefgroupid: $(this).val()}); + }); +}); +params['dms']; + $selgroup = $this->params['selattrdefgroup']; + $cachedir = $this->params['cachedir']; + $previewwidth = $this->params['previewWidthList']; + $workflowmode = $this->params['workflowmode']; + $timeout = $this->params['timeout']; + + if($selgroup) { + $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout); + $this->contentHeading(getMLText("group_info")); + + $folders = $selgroup->getFolders(); + print ""; + print "\n\n"; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + print "\n\n\n"; + foreach($folders as $subFolder) { + echo $this->folderListRow($subFolder); + } + echo "\n
".getMLText("name")."".getMLText("status")."".getMLText("action")."
\n"; + } + } /* }}} */ + + function showAttributeGroupForm($group) { /* {{{ */ + $dms = $this->params['dms']; + $user = $this->params['user']; + $allUsers = $this->params['attrdefs']; + $groups = $this->params['attrdefgroups']; +?> +
+ + + + + + + +check_access('RemoveAttributeDefinitionGroup')) { +?> + + + + + + + + + + + + + + + + + +
html_link('RemoveAttributeDefinitionGroup', array('attrdefgroupid'=>$group->getID()), array('class'=>'btn'), ' '.getMLText("rm_attrdefgroup"), false); ?>
:
:
+
+contentSubHeading(getMLText("group_members")); +?> + +getAttributeDefinitions(); + if (count($members) == 0) + print ""; + else { + $seqs = array(); + $i = 0; + foreach ($members as $member) { + $seqs[$i] = $group->getSequence($member); + $i++; + } + + $i = 0; + foreach ($members as $member) { + $seq = $seqs[$i]; + $pseq = isset($seqs[$i-1]) ? $seqs[$i-1] : $seqs[$i] - 20.0; + $ppseq = isset($seqs[$i-2]) ? $seqs[$i-2] : $pseq - 20.0; + $nseq = isset($seqs[$i+1]) ? $seqs[$i+1] : $seqs[$i] + 20.0; + $nnseq = isset($seqs[$i+2]) ? $seqs[$i+2] : $nseq + 20.0; + + $newupseq = ($pseq-$ppseq)/2+$ppseq; + $newdownseq = ($nnseq-$nseq)/2+$nseq; + + switch($member->getObjType()) { + case SeedDMS_Core_AttributeDefinition::objtype_all: + $ot = getMLText("all"); + break; + case SeedDMS_Core_AttributeDefinition::objtype_folder: + $ot = getMLText("folder"); + break; + case SeedDMS_Core_AttributeDefinition::objtype_document: + $ot = getMLText("document"); + break; + case SeedDMS_Core_AttributeDefinition::objtype_documentcontent: + $ot = getMLText("version"); + break; + } + switch($member->getType()) { + case SeedDMS_Core_AttributeDefinition::type_int: + $t = getMLText("attrdef_type_int"); + break; + case SeedDMS_Core_AttributeDefinition::type_float: + $t = getMLText("attrdef_type_float"); + break; + case SeedDMS_Core_AttributeDefinition::type_string: + $t = getMLText("attrdef_type_string"); + break; + case SeedDMS_Core_AttributeDefinition::type_date: + $t = getMLText("attrdef_type_date"); + break; + case SeedDMS_Core_AttributeDefinition::type_boolean: + $t = getMLText("attrdef_type_boolean"); + break; + } + print ""; + print ""; + print ""; + print ""; + print ""; + $i++; + } + } +?> +
".getMLText("no_group_members")."
" . htmlspecialchars($member->getName()) ." (".$ot.", ".$t.")".""; + $show = $group->getShow($member); + $shows = array(); + for($i=0; $i<4; $i++) { + if(1 << $i & $show) + $shows[] = 1 << $i; + } + print "
getID()."\" />getID()."\" />".createHiddenFieldWithKey('setshow'); + echo " "; + print "
"; + print "
"; + if($i != 0) + print "
getID()."\" />getID()."\" />".createHiddenFieldWithKey('setsequence')."
"; + print "
"; + if($i < count($members)-1) + print "
getID()."\" />getID()."\" />".createHiddenFieldWithKey('setsequence')."
"; + print "
"; + print "
getID()."\" />getID()."\" />".createHiddenFieldWithKey('rmmember')."
"; + print "
+ +contentSubHeading(getMLText("add_member")); +?> + +
+ + + + + + + + + +
+ + + + + "> +
+
+params['selattrdefgroup']; + + $this->showAttributeGroupForm($selgroup); + } /* }}} */ + + function show() { /* {{{ */ + $dms = $this->params['dms']; + $user = $this->params['user']; + $accessop = $this->params['accessobject']; + $selgroup = $this->params['selattrdefgroup']; + $allGroups = $this->params['attrdefgroups']; + $strictformcheck = $this->params['strictformcheck']; + + $this->htmlStartPage(getMLText("admin_tools")); + $this->globalNavigation(); + $this->contentStart(); + $this->pageNavigation(getMLText("admin_tools"), "admin_tools"); + + $this->contentHeading(getMLText("attrdefgroup_management")); +?> + +
+
+
+: + +
+check_view_access($this, array('action'=>'info'))) { ?> +
getID()."\"" : "") ?>>
+ +
+ +
+
+check_view_access($this, array('action'=>'form'))) { ?> +
getID()."\"" : "") ?>>
+ +
+
+ +
+ +contentEnd(); + $this->htmlEndPage(); + } /* }}} */ +} +?> diff --git a/views/bootstrap/class.Bootstrap.php b/views/bootstrap/class.Bootstrap.php index dcb185c68..b99be130c 100644 --- a/views/bootstrap/class.Bootstrap.php +++ b/views/bootstrap/class.Bootstrap.php @@ -1096,6 +1096,8 @@ background-image: linear-gradient(to bottom, #882222, #111111);; $menuitems['definitions']['children']['document_categories'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Categories.php", 'label'=>getMLText('global_document_categories')); if ($accessobject->check_view_access('AttributeMgr')) $menuitems['definitions']['children']['attribute_definitions'] = array('link'=>$this->params['settings']->_httpRoot."out/out.AttributeMgr.php", 'label'=>getMLText('global_attributedefinitions')); + if ($accessobject->check_view_access('AttributeGroupMgr')) + $menuitems['definitions']['children']['attributegroup_definitions'] = array('link'=>$this->params['settings']->_httpRoot."out/out.AttributeGroupMgr.php", 'label'=>getMLText("global_attributedefinitiongroups")); if($this->params['workflowmode'] == 'advanced') { if ($accessobject->check_view_access('WorkflowMgr')) $menuitems['definitions']['children']['workflows'] = array('link'=>$this->params['settings']->_httpRoot."out/out.WorkflowMgr.php", 'label'=>getMLText('global_workflows')); diff --git a/views/bootstrap/class.EditFolder.php b/views/bootstrap/class.EditFolder.php index b7a47f479..7378cec23 100644 --- a/views/bootstrap/class.EditFolder.php +++ b/views/bootstrap/class.EditFolder.php @@ -52,6 +52,7 @@ $(document).ready(function() { $user = $this->params['user']; $folder = $this->params['folder']; $attrdefs = $this->params['attrdefs']; + $attrdefgrps = $this->params['attrdefgrps']; $rootfolderid = $this->params['rootfolderid']; $strictformcheck = $this->params['strictformcheck']; $nofolderformfields = $this->params['nofolderformfields']; @@ -111,9 +112,38 @@ $(document).ready(function() { $this->formField(getMLText("sequence"), $this->getSequenceChooser($parent, 'f', $folder->getID()).($orderby != 's' ? "
".getMLText('order_by_sequence_off') : '')); } } - if($attrdefs) { + + if($attrdefgrps) { + foreach($attrdefgrps as $attrdefgrp) { + $attrdefs = $attrdefgrp['group']->getAttributeDefinitions(array(SeedDMS_Core_AttributeDefinition::objtype_all, SeedDMS_Core_AttributeDefinition::objtype_folder)); + echo "".htmlspecialchars($attrdefgrp['group']->getComment()).""; + foreach($attrdefs as $attrdef) { + $arr = $this->callHook('folderEditAttribute', $folder, $attrdef); + if(is_array($arr)) { + echo $txt; + echo ""; + echo "".$arr[0].""; + echo "".$arr[1].""; + echo ""; + } else { +?> + + getName()); ?> + printAttributeEditField($attrdef, $folder->getAttribute($attrdef)) ?> + +callHook('editFolderAttribute', $folder, $attrdef); + $found = false; + foreach($attrdefgrps as $attrdefgrp) { + if($attrdefgrp['group']->isMember($attrdef)) + $found = true; + } + if($found) { + $arr = $this->callHook('folderEditAttribute', $folder, $attrdef); if(is_array($arr)) { if($arr) { $this->formField($arr[0], $arr[1], isset($arr[2]) ? $arr[2] : null); @@ -123,6 +153,16 @@ $(document).ready(function() { } else { $this->formField(htmlspecialchars($attrdef->getName()), $this->getAttributeEditField($attrdef, $folder->getAttribute($attrdef))); } + } else { + if($attribute = $folder->getAttribute($attrdef)) { +?> + + getName()); ?> + getValue() ?> + +callHook('addFolderAttributes', $folder); diff --git a/views/bootstrap/class.FolderAttributeGroup.php b/views/bootstrap/class.FolderAttributeGroup.php new file mode 100644 index 000000000..adece16fd --- /dev/null +++ b/views/bootstrap/class.FolderAttributeGroup.php @@ -0,0 +1,147 @@ + + * @copyright Copyright (C) 202-2005 Markus Westphal, + * 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli, + * 2010-2016 Uwe Steinmann + * @version Release: @package_version@ + */ + +/** + * Include parent class + */ +require_once("class.Bootstrap.php"); + +/** + * Class which outputs the html page for FolderAttributeGroup view + * + * @category DMS + * @package SeedDMS + * @author Markus Westphal, Malcolm Cowe, Uwe Steinmann + * @copyright Copyright (C) 2002-2005 Markus Westphal, + * 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli, + * 2010-2016 Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_View_FolderAttributeGroup extends SeedDMS_Bootstrap_Style { + + function js() { /* {{{ */ + header('Content-Type: application/javascript; charset=UTF-8'); +?> +function checkForm() +{ + msg = new Array(); + if ((document.form1.userid.options[document.form1.userid.selectedIndex].value == -1) && + (document.form1.groupid.options[document.form1.groupid.selectedIndex].value == -1)) + msg.push(""); + if (msg != "") { + noty({ + text: msg.join('
'), + type: 'error', + dismissQueue: true, + layout: 'topRight', + theme: 'defaultTheme', + _timeout: 1500, + }); + return false; + } + else + return true; +} +$(document).ready(function() { + $('body').on('submit', '#form1', function(ev){ + if(checkForm()) return; + ev.preventDefault(); + }); +}); +params['dms']; + $user = $this->params['user']; + $folder = $this->params['folder']; + $allGroups = $this->params['allattrgrps']; + $strictformcheck = $this->params['strictformcheck']; + + $attrgrpList = $folder->getAttributeDefintionGroupList(); + + $this->htmlStartPage(getMLText("folder_title", array("foldername" => htmlspecialchars($folder->getName())))); + $this->globalNavigation($folder); + $this->contentStart(); + $this->pageNavigation($this->getFolderPathHTML($folder, true), "view_folder", $folder); + + $this->contentHeading(getMLText("edit_existing_attribute_groups")); + $this->contentContainerStart(); + + $attrgrpIDs = array(); + + print "\n"; + if (empty($attrgrpList)) { + print ""; + } + else { + + foreach ($attrgrpList as $attrgrp) { + print ""; + print ""; + print ""; + if ($user->isAdmin()) { + print "\n"; + echo createHiddenFieldWithKey('folderattributegroup')."\n"; + print "getID()."\">\n"; + print "\n"; + print "getID()."\">\n"; + print ""; + print "\n"; + }else print ""; + print ""; + $attrgrpIDs[] = $attrgrp['group']->getID(); + } + } + print "
".getMLText("empty_attribute_group_list")."
" . htmlspecialchars($attrgrp['group']->getName()) . "
"; + print ""; + print "
\n"; + +?> +
+
+ + + + + + + + + + + + +
: + +
">
+
+ +contentContainerEnd(); + $this->contentEnd(); + $this->htmlEndPage(); + } /* }}} */ +} +?>