|
@@ -17,6 +17,7 @@ class AntAclBase extends Core_AclBase {
|
|
|
$this->_rootNamespace = '';
|
|
|
$this->_primaryKey = '';
|
|
|
$this->_fields = [];
|
|
|
+ $this->_xsdRestrictions = [];
|
|
|
$this->_zasobyInfoFetched = false;
|
|
|
}
|
|
|
public function getDB() { return $this->_db; }
|
|
@@ -168,13 +169,12 @@ class AntAclBase extends Core_AclBase {
|
|
|
}
|
|
|
public function getFieldIdByName($fieldName) {
|
|
|
if (!$fieldName) return null;
|
|
|
- $idZasob = null;
|
|
|
foreach ($this->getFields() as $field) {
|
|
|
- if ($fieldName === $field['name']) {
|
|
|
- if ($field['idZasob']) $idZasob = $field['idZasob'];
|
|
|
- }
|
|
|
+ if ($fieldName !== $field['name']) continue;
|
|
|
+ if (!$field['idZasob']) continue;
|
|
|
+ return $field['idZasob'];
|
|
|
}
|
|
|
- return $idZasob;
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
public function getFieldType($fieldName) { return null; }
|
|
@@ -203,17 +203,38 @@ class AntAclBase extends Core_AclBase {
|
|
|
}
|
|
|
public function getXsdMaxOccurs($fieldName) {
|
|
|
$field = $this->_getField($fieldName);
|
|
|
- return $field['maxOccurs'];
|
|
|
+ return (int)$field['maxOccurs'];
|
|
|
}
|
|
|
public function getXsdMinOccurs($fieldName) {
|
|
|
$field = $this->_getField($fieldName);
|
|
|
- return $field['minOccurs'];
|
|
|
+ return (int)$field['minOccurs'];
|
|
|
}
|
|
|
public function getAttributesFromZasoby() {
|
|
|
return [];// TODO: ...
|
|
|
}
|
|
|
- public function getXsdFieldParam($fieldName, $paramKey) { // TODO: fetch from db
|
|
|
- return null;
|
|
|
+ public function getXsdFieldParam($fieldName, $paramKey) {
|
|
|
+ switch ($paramKey) {
|
|
|
+ case 'enumeration': return $this->getEnumerations($fieldName);
|
|
|
+ }
|
|
|
+ $xsdType = $this->getXsdFieldType($fieldName);
|
|
|
+ $defaultValue = null;
|
|
|
+ if ('enumeration' === $paramKey && 'p5:enum' === $xsdType) $defaultValue = [];
|
|
|
+ if ('maxLength' === $paramKey && 'xsd:string' === $xsdType) $defaultValue = 255;
|
|
|
+ return V::get($paramKey, $defaultValue, $this->getXsdRestrictions($fieldName));
|
|
|
+ }
|
|
|
+ public function getEnumerations($fieldName) {
|
|
|
+ $restrictions = $this->getXsdRestrictions($fieldName);
|
|
|
+ return V::get('enumeration', [], $restrictions, 'array');
|
|
|
+ }
|
|
|
+ public function getXsdRestrictions($fieldName) {
|
|
|
+ if (array_key_exists($fieldName, $this->_xsdRestrictions)) return $this->_xsdRestrictions[$fieldName];
|
|
|
+ $this->_xsdRestrictions[$fieldName] = [];
|
|
|
+ $field = $this->_getField($fieldName);
|
|
|
+ if (!$field['xsdRestrictions']) return [];
|
|
|
+ if (is_string($field['xsdRestrictions']) && '{' === substr($field['xsdRestrictions'], 0, 1)) {
|
|
|
+ $this->_xsdRestrictions[$fieldName] = @json_decode($field['xsdRestrictions'], $assoc = true);
|
|
|
+ }
|
|
|
+ return $this->_xsdRestrictions[$fieldName];
|
|
|
}
|
|
|
// public function getXsdFieldParam($fieldName, $paramKey) { // TableAcl
|
|
|
// return ($this->_schemaClass)
|
|
@@ -228,16 +249,79 @@ class AntAclBase extends Core_AclBase {
|
|
|
// return $this->_simpleSchema['root'][$fieldName]['@@params'][$paramKey];
|
|
|
// }
|
|
|
|
|
|
+ public function getFieldDefaultValue($fieldName) { // TODO: get dafault value from xsd file - TODO: p5:default attribute
|
|
|
+ // TODO: get from xsd file (acl cache field)
|
|
|
+ // TODO: if not set then:
|
|
|
+ // - 'NULL' for nillable fields
|
|
|
+ // - '0' for xsd:integer, xsd:decimal
|
|
|
+ // - '' else ...
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ public function convertObjectFromUserInput($userItem, $type = 'array_by_id', $prefix = 'f') {// TODO: rename / Legacy
|
|
|
+ $item = $this->parseUserItem($userItem, $type = 'array_by_id', $prefix = 'f');
|
|
|
+ foreach ($item as $fieldName => $value) {
|
|
|
+ $item[$fieldName] = $this->validateAndFixField($fieldName, $value);
|
|
|
+ }
|
|
|
+ DBG::log(['userItem' => $userItem, 'item' => $item], 'array', "after parseUserItem, validateAndFixField");
|
|
|
+ return $item;
|
|
|
+ }
|
|
|
+ public function parseUserItem($userItem, $type = 'array_by_id', $prefix = 'f') {
|
|
|
+ $item = [];
|
|
|
+ foreach ($this->getFieldListByIdZasob() as $userKey => $fieldName) {
|
|
|
+ if (!array_key_exists("f{$userKey}", $userItem)) continue;
|
|
|
+ $item[$fieldName] = $userItem["f{$userKey}"];
|
|
|
+ }
|
|
|
+ return $item;
|
|
|
+ }
|
|
|
+ public function validateAndFixField($fieldName, $value) {
|
|
|
+ if (empty($value) && 0 === strlen($value)) {// TODO: fixEmptyValueFromUser
|
|
|
+ return $this->fixFieldEmptyValue($fieldName);
|
|
|
+ }
|
|
|
+ $xsdType = $this->getXsdFieldType($fieldName);
|
|
|
+ switch ($xsdType) {
|
|
|
+ case 'xsd:decimal': return str_replace([',', ' '], ['.', ''], $value);
|
|
|
+ case 'p5:price': return V::convert($value, 'price');
|
|
|
+ }
|
|
|
+ return $value;
|
|
|
+ }
|
|
|
+ public function fixFieldEmptyValue($fieldName) {// TODO: legacy - TODO: FIX
|
|
|
+ return $this->getFieldDefaultValue($fieldName);
|
|
|
+ // $value = '';
|
|
|
+ // $xsdType = $this->getXsdFieldType($fieldName);
|
|
|
+ // // $type = $this->getFieldType($fieldName); // TODO: RM
|
|
|
+ // // if (!$type) return '';
|
|
|
+ // if ('xsd:date' === $xsdType) return $this->getFieldDefaultValue($fieldName);
|
|
|
+ // if ('xsd:integer' === $xsdType) return (int)$this->getFieldDefaultValue($fieldName);
|
|
|
+ // // fix bug when field is unique and is null allowed: change empty string to null
|
|
|
+ // if ($type['null']) {
|
|
|
+ // $value = 'NULL';
|
|
|
+ // }
|
|
|
+ // // fix bug when field is enum and is set to '0': for php '0' is empty
|
|
|
+ // if (substr($type['type'], 0, 4) == 'enum') {// && $args["f{$fieldID}"] === '0') {
|
|
|
+ // // if (false !== strpos($type['type'], "''")) {
|
|
|
+ // // // enum('', '1','2')
|
|
|
+ // // $value = '';
|
|
|
+ // // } else if (false !== strpos($type['type'], "'0'")) {
|
|
|
+ // // // enum('0', '1','2')
|
|
|
+ // // $value = '0';
|
|
|
+ // // } else {
|
|
|
+ // $value = $this->getFieldDefaultValue($fieldName);
|
|
|
+ // // }
|
|
|
+ // }
|
|
|
+ // return $value;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
public function isGeomField($fieldName) {
|
|
|
return ('the_geom' === $fieldName); // TODO: check by xsdType
|
|
|
}
|
|
|
public function isEnumerationField($fieldName) {
|
|
|
- return false; // TODO: ...
|
|
|
+ $xsdType = $this->getXsdFieldType($fieldName);
|
|
|
+ if ('p5:enum' === $xsdType) return true;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- public function canWriteField($fieldName) {
|
|
|
- return false; // TODO: $this->getAclInfo($fieldName); @see canReadField
|
|
|
- }
|
|
|
public function canCreateField($fieldName) {
|
|
|
try {
|
|
|
$fieldAclInfo = $this->getAclInfo($fieldName);
|
|
@@ -251,6 +335,11 @@ class AntAclBase extends Core_AclBase {
|
|
|
}
|
|
|
public function canReadField($fieldName) {
|
|
|
try {
|
|
|
+ if ('A_RECORD_CREATE_DATE' === $fieldName) return true;
|
|
|
+ if ('A_RECORD_CREATE_AUTHOR' === $fieldName) return true;
|
|
|
+ if ('A_RECORD_UPDATE_DATE' === $fieldName) return true;
|
|
|
+ if ('A_RECORD_UPDATE_AUTHOR' === $fieldName) return true;
|
|
|
+ if ($this->getPrimaryKeyField() === $fieldName) return true;
|
|
|
$fieldAclInfo = $this->getAclInfo($fieldName);
|
|
|
DBG::log($fieldAclInfo, 'array', "AntAclBase: canReadField({$fieldName})...");
|
|
|
return ($fieldAclInfo['PERM_R'] > 0 || $fieldAclInfo['PERM_V'] > 0 || $fieldAclInfo['PERM_O'] > 0);
|
|
@@ -261,10 +350,43 @@ class AntAclBase extends Core_AclBase {
|
|
|
return false;
|
|
|
}
|
|
|
public function canReadObjectField($fieldName, $object) {
|
|
|
- return true; // TODO: $this->getAclInfo($fieldName); @see canReadField
|
|
|
+ try {
|
|
|
+ if ('A_RECORD_CREATE_DATE' === $fieldName) return true;
|
|
|
+ if ('A_RECORD_CREATE_AUTHOR' === $fieldName) return true;
|
|
|
+ if ('A_RECORD_UPDATE_DATE' === $fieldName) return true;
|
|
|
+ if ('A_RECORD_UPDATE_AUTHOR' === $fieldName) return true;
|
|
|
+ if ($this->getPrimaryKeyField() === $fieldName) return true;
|
|
|
+ $fieldAclInfo = $this->getAclInfo($fieldName);
|
|
|
+ DBG::log([$fieldAclInfo, 'V' => ($fieldAclInfo['PERM_V'] > 0), 'R'=>($fieldAclInfo['PERM_R'] > 0 && $this->canReadRecord($record)), 'O'=>($fieldAclInfo['PERM_O'] > 0 && $this->canReadRecord($record))], 'array', "AntAclBase: canWriteObjectField({$fieldName})...");
|
|
|
+ if ($fieldAclInfo['PERM_V'] > 0) return true;
|
|
|
+ if ($fieldAclInfo['PERM_R'] > 0 && $this->canReadRecord($record)) return true;
|
|
|
+ if ($fieldAclInfo['PERM_O'] > 0 && $this->canReadRecord($record)) return true;
|
|
|
+ } catch (Exception $e) {
|
|
|
+ DBG::log($e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ public function canWriteField($fieldName) {
|
|
|
+ try {
|
|
|
+ $fieldAclInfo = $this->getAclInfo($fieldName);
|
|
|
+ DBG::log($fieldAclInfo, 'array', "AntAclBase: canReadField({$fieldName})...");
|
|
|
+ if ($fieldAclInfo['PERM_W'] > 0 || $fieldAclInfo['PERM_S'] > 0) return true;
|
|
|
+ } catch (Exception $e) {
|
|
|
+ DBG::log($e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
public function canWriteObjectField($fieldName, $record) {
|
|
|
- return false; // TODO: $this->getAclInfo($fieldName); @see canReadField
|
|
|
+ try {
|
|
|
+ $fieldAclInfo = $this->getAclInfo($fieldName);
|
|
|
+ DBG::log($fieldAclInfo, 'array', "AntAclBase: canWriteObjectField({$fieldName})...");
|
|
|
+ DBG::log([$fieldAclInfo, 'S' => $fieldAclInfo['PERM_S'] > 0, 'W'=>$fieldAclInfo['PERM_W'], 'canWrite'=>$this->canWriteRecord($record), $record], 'array', "AntAclBase: canWriteObjectField({$fieldName})...");
|
|
|
+ if ($fieldAclInfo['PERM_S'] > 0) return true;
|
|
|
+ if ($fieldAclInfo['PERM_W'] > 0 && $this->canWriteRecord($record)) return true;
|
|
|
+ } catch (Exception $e) {
|
|
|
+ DBG::log($e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
public function getAclInfo($fieldName = null) {
|
|
|
static $_aclInfo = []; // [ fieldName => [ id => {idZasob}, perms => 'RWX...' ] // TODO: , sort_prio => {SORT_PRIO}, label => {CELL_LABEL} ]
|
|
@@ -290,6 +412,86 @@ class AntAclBase extends Core_AclBase {
|
|
|
return ($fieldName) ? $_aclInfo[ $this->getID() ][ $fieldName ] : $_aclInfo[ $this->getID() ];
|
|
|
}
|
|
|
|
|
|
+ public function hasFieldPerm($fieldID, $perm) { // TODO: legacy
|
|
|
+ $field = $this->getField();
|
|
|
+ if (!$field) return false;
|
|
|
+ try {
|
|
|
+ $fieldAclInfo = $this->getAclInfo($fieldName);
|
|
|
+ DBG::log($fieldAclInfo, 'array', "AntAclBase: hasFieldPerm({$fieldName})...");
|
|
|
+ if (!array_key_exists("PERM_{$perm}", $fieldAclInfo)) return false;
|
|
|
+ return ($fieldAclInfo["PERM_{$perm}"] > 0);
|
|
|
+ } catch (Exception $e) {
|
|
|
+ DBG::log($e);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ public function isAllowed($fieldID, $taskPerm, $record = null) {// TODO: legacy - replace with canWriteField, canReadField, canWriteObjectField, canReadObjectField, canCreateField
|
|
|
+ $field = $this->getField($fieldID);
|
|
|
+ if (!$field) return false;
|
|
|
+ $fieldName = $field['name'];
|
|
|
+
|
|
|
+ switch ($taskPerm) {
|
|
|
+ case 'C': return false; // 'PERM_C'
|
|
|
+ case 'R': return ($record) ? $this->canReadObjectField($fieldName, $record) : $this->canReadField($fieldName);
|
|
|
+ case 'W': return ($record) ? $this->canWriteObjectField($fieldName, $record) : $this->canWriteField($fieldName);
|
|
|
+ default: throw new Exception("Not Implemented isAllowed perm '{$taskPerm}'");
|
|
|
+ }
|
|
|
+
|
|
|
+ $adminFields = array();
|
|
|
+ $adminFields[] = $this->getPrimaryKeyField();
|
|
|
+ $adminFields[] = 'A_RECORD_CREATE_DATE';
|
|
|
+ $adminFields[] = 'A_RECORD_CREATE_AUTHOR';
|
|
|
+ $adminFields[] = 'A_RECORD_UPDATE_DATE';
|
|
|
+ $adminFields[] = 'A_RECORD_UPDATE_AUTHOR';
|
|
|
+ if ($taskPerm == 'R' && in_array($fieldName, $adminFields)) return true;
|
|
|
+ if ($taskPerm == 'W' && in_array($fieldName, $adminFields)) return false;
|
|
|
+
|
|
|
+ // check perm: allow 'RS', 'WS' - can R/W field even if cant read record
|
|
|
+ // check 'O' - can read field even if cant read field but can read record
|
|
|
+ DBG::log([
|
|
|
+ 'record' => $record,
|
|
|
+ 'canReadRecord' => $this->canReadRecord($record),
|
|
|
+ 'hasFieldPerm(O) || canWriteRecord'=>'"'.$this->hasFieldPerm($fieldID, 'O').'" || "'.$this->canReadRecord($record).'"',
|
|
|
+ 'hasFieldPerm(S)'=>'"'.$this->hasFieldPerm($fieldID, 'S').'"',
|
|
|
+ 'hasFieldPerm(V)'=>'"'.$this->hasFieldPerm($fieldID, 'V').'"',
|
|
|
+ ], 'array', "isAllowed({$fieldName}[{$fieldID}], {$taskPerm})");
|
|
|
+
|
|
|
+ if (!$this->hasFieldPerm($fieldID, $taskPerm)) {
|
|
|
+ if ($taskPerm == 'R' && $this->hasFieldPerm($fieldID, 'V')) {
|
|
|
+ return true;
|
|
|
+ } else if ($taskPerm == 'R'
|
|
|
+ && $record
|
|
|
+ && $this->hasFieldPerm($fieldID, 'O')
|
|
|
+ && ($this->canReadRecord($record) || $this->canWriteRecord($record))
|
|
|
+ ) {
|
|
|
+ return true;// 'WO' or 'CO'
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // check 'R' - require can read record, or V - Super View
|
|
|
+ if ($taskPerm == 'R') {
|
|
|
+ if ($this->canReadRecord($record) || $this->hasFieldPerm($fieldID, 'V')) {
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // // 'C' and 'W' require colType
|
|
|
+ // $colType = $this->getFieldTypeById($fieldID);
|
|
|
+ // if (!$colType) {
|
|
|
+ // return false;
|
|
|
+ // }
|
|
|
+ if ($taskPerm == 'W') {
|
|
|
+ if ($record) {
|
|
|
+ if(V::get('DBG_ACL', '', $_REQUEST) > 1){echo '(Field: '.$fieldID.', canWriteRecord: ' . $this->canWriteRecord($record) . ' || (hasFieldPerm(S): ' . $this->hasFieldPerm($fieldID, 'S') . ' && hasFieldPerm(W): ' . $this->hasFieldPerm($fieldID, 'W') . '))';}
|
|
|
+ return ($this->canWriteRecord($record) || $this->hasFieldPerm($fieldID, 'S'));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
public function getFields() { // TODO: conflict return structure with TableAcl
|
|
|
if (empty($this->_fields)) {
|
|
|
// TODO: fetch fields from DB
|
|
@@ -421,4 +623,78 @@ class AntAclBase extends Core_AclBase {
|
|
|
public function init($force = false) { }
|
|
|
public function isInitialized($force = false) { return true; }
|
|
|
|
|
|
+ public function updateItem($itemPatch) {
|
|
|
+ if (is_object($itemPatch)) {
|
|
|
+ $itemPatch = (array)$itemPatch;
|
|
|
+ } else if (!is_array($itemPatch)) {
|
|
|
+ throw new HttpException('Item patch is not array', 400);
|
|
|
+ }
|
|
|
+ if (empty($itemPatch)) {
|
|
|
+ DBG::log("Item patch is empty - after validation");
|
|
|
+ // throw new Exception('Item patch is empty');
|
|
|
+ return 0;// nothing to change
|
|
|
+ }
|
|
|
+
|
|
|
+ $primaryKeyField = $this->getPrimaryKeyField();
|
|
|
+ if (empty($itemPatch[$primaryKeyField])) throw new HttpException("Item Primary Key not set!", 400);
|
|
|
+
|
|
|
+ $primaryKey = $itemPatch[$primaryKeyField];
|
|
|
+ $itemOld = (array)$this->getItem($primaryKey);
|
|
|
+ if (!$itemOld) throw new HttpException("Item not exists!", 404);
|
|
|
+
|
|
|
+ if (!$this->canWriteRecord($itemOld) && !$this->hasPermSuperWrite()) throw new HttpException("Brak dostępu do rekordu", 403);
|
|
|
+
|
|
|
+ // $itemPatch from user input to $validPatch
|
|
|
+ $validPatch = array();
|
|
|
+ DBG::log($itemPatch, 'array', "Item patch - before validation");
|
|
|
+ foreach ($this->getFieldListByIdZasob() as $kID => $fieldName) {
|
|
|
+ if (!array_key_exists($fieldName, $itemPatch)) continue;
|
|
|
+ if (!$this->isAllowed($kID, 'W', $itemOld)) continue;
|
|
|
+ // default value for perms 'W' without 'R' is '*****'
|
|
|
+ if (!$this->isAllowed($kID, 'R', $itemOld) && '*****' == $itemPatch[$fieldName]) continue;
|
|
|
+
|
|
|
+ $value = $itemPatch[$fieldName];
|
|
|
+ if (empty($itemPatch[$fieldName]) && strlen($itemPatch[$fieldName]) == 0) {// fix bug in input type date and value="0000-00-00"
|
|
|
+ $value = $this->fixFieldEmptyValue($fieldName);
|
|
|
+ }
|
|
|
+ if ($value != $itemOld[$fieldName]) {
|
|
|
+ $validPatch[$fieldName] = $value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ DBG::log($validPatch, 'array', "Item patch - after validation");
|
|
|
+ if (empty($validPatch)) {
|
|
|
+ DBG::log("Item patch is empty - after validation");
|
|
|
+ // throw new Exception('Item patch is empty');
|
|
|
+ return 0;// nothing to change
|
|
|
+ }
|
|
|
+
|
|
|
+ DBG::log($validPatch, 'array', "TODO: EDIT valid item patch");
|
|
|
+ $affected = DB::getPDO()->update($this->getRootTableName(), $primaryKeyField, $primaryKey, array_merge(
|
|
|
+ $validPatch,
|
|
|
+ [
|
|
|
+ 'A_RECORD_UPDATE_DATE' => 'NOW()',
|
|
|
+ 'A_RECORD_UPDATE_AUTHOR' => User::getLogin(),
|
|
|
+ ]
|
|
|
+ ));
|
|
|
+ if ($affected) {
|
|
|
+ $affected += $this->saveUpdateHist(array_merge(
|
|
|
+ $validPatch,
|
|
|
+ [
|
|
|
+ 'ID_USERS2' => $primaryKey,
|
|
|
+ 'A_RECORD_UPDATE_DATE' => 'NOW()',
|
|
|
+ 'A_RECORD_UPDATE_AUTHOR' => User::getLogin(),
|
|
|
+ ]
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ return $affected;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function saveUpdateHist($histPatch) {
|
|
|
+ try {
|
|
|
+ $idHist = DB::getPDO()->insert($this->getRootTableName() . '_HIST', $histPatch);
|
|
|
+ } catch (Exception $e) {
|
|
|
+ DBG::log($e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|