UserObjectStorageAcl.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <?php
  2. Lib::loadClass('Core_AclSimpleSchemaBase');
  3. Lib::loadClass('ParseOgcFilter');
  4. Lib::loadClass('UsersHelper');
  5. /**
  6. * @require CRM_PROCES_idx_TABLE_TO_PROCES_GROUPED_VIEW from FixCrmProcesInitIdx
  7. * @require idUser (ref from parent object - User)
  8. */
  9. class Schema_UserObjectStorageAcl extends Core_AclSimpleSchemaBase {
  10. public $_simpleSchema = [
  11. 'root' => [
  12. '@namespace' => 'default_objects/UserObject',
  13. '@primaryKey' => 'ID_TABLE',
  14. // 'ID' => [ '@type' => 'xsd:string', '@aliasSqlConcat' => ['{table}.ID_TABLE', '-', '{table}.ID_USER', '-', '{table}.ID_PROCES'] ],
  15. 'ID_TABLE' => [ '@type' => 'xsd:integer' ], // `ID_TABLE` int(11) NOT NULL,
  16. 'ID_USER' => [ '@type' => 'xsd:integer' ], // `ID_USER` int(11) NOT NULL,
  17. 'ID_PROCES' => [ '@type' => 'xsd:integer' ], // `ID_PROCES` int(11) DEFAULT NULL,
  18. 'db' => [ '@type' => 'xsd:integer' ], // `db` int(11) NOT NULL,
  19. 'name' => [ '@type' => 'xsd:string' ], // `name` varchar(255) DEFAULT '',
  20. 'label' => [ '@type' => 'xsd:string' ], // `label` varchar(255) DEFAULT '',
  21. 'opis' => [ '@type' => 'xsd:string' ], // `opis` text,
  22. '_rootTableName' => [ '@type' => 'xsd:string' ], // `ROOT_TABLE_NAME` varchar(255) DEFAULT '',
  23. 'A_LAST_SYNC' => [ '@type' => 'xsd:dateTime' ], // `A_LAST_SYNC` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  24. // TODO: UNIQUE KEY `uniq` (ID_USER, ID_URL, ID_PROCES)
  25. ]
  26. ];
  27. public $_rootTableName = 'CRM_AUTH_#CACHE_ACL_OBJECT';
  28. public $idUser = null;
  29. public $idProcesFilter = null;
  30. public function __construct($simpleSchema = null) {
  31. parent::__construct($simpleSchema);
  32. $this->idUser = User::getID();// default - current user
  33. }
  34. public function setIdUser($idUser) {
  35. $this->idUser = intval($idUser);
  36. if ($this->idUser <= 0) throw new Exception("Missing id user");
  37. }
  38. public function getIdUser() { return $this->idUser; }
  39. public function setIdProcesFilter($idProcesFilter) { $this->idProcesFilter = intval($idProcesFilter); }
  40. public function getIdProcesFilter() { return $this->idProcesFilter; }
  41. public function updateCacheFeatures() {
  42. $dbName = DB::getPDO()->getDatabaseName();
  43. $idDatabase = DB::getPDO()->getZasobId();
  44. $sqlIdProces = ($this->idProcesFilter > 0) ? $this->idProcesFilter : 'NULL';
  45. $sqlWhereAndIdProces = ($this->idProcesFilter > 0) ? "and c.ID_PROCES = {$this->idProcesFilter}" : "and c.ID_PROCES is NULL";
  46. $sqlNoPrefixWhereAndIdProces = ($this->idProcesFilter > 0) ? "and ID_PROCES = {$this->idProcesFilter}" : "and ID_PROCES is NULL";
  47. $sqlIdProcesListSql = $this->getUsedUserProcesIdsSql();
  48. DB::getPDO()->execSql("
  49. create table if not exists `{$this->_rootTableName}` (
  50. `ID_USER` int(11) NOT NULL,
  51. `ID_TABLE` int(11) NOT NULL,
  52. `ID_PROCES` int(11) DEFAULT NULL,
  53. `db` int(11) NOT NULL,
  54. `name` varchar(255) DEFAULT '',
  55. `label` varchar(255) DEFAULT '',
  56. `opis` text,
  57. `ROOT_TABLE_NAME` varchar(255) DEFAULT '',
  58. `A_LAST_SYNC` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  59. UNIQUE KEY `uniq` (ID_USER, ID_TABLE, ID_PROCES)
  60. ) ENGINE=MyISAM DEFAULT CHARSET=latin2
  61. ");
  62. DB::getPDO()->execSql(" delete from `{$this->_rootTableName}` where ID_USER = {$this->idUser} {$sqlNoPrefixWhereAndIdProces} ");
  63. if ($sqlIdProcesListSql) {
  64. DB::getPDO()->execSql("
  65. insert into `{$this->_rootTableName}` (ID_USER, A_LAST_SYNC, ID_PROCES, ID_TABLE, db, name, label, opis)
  66. select {$this->idUser}
  67. , NOW()
  68. , {$sqlIdProces}
  69. , tpvg.`ID_TABLE`
  70. , tpvg.`ID_DATABASE` as `db`
  71. , tpvg.`TABLE_NAME` as `name`
  72. , tpvg.`TABLE_LABEL` as `label`
  73. , tpvg.`TABLE_DESCRIPTION` as `opis`
  74. from `CRM_PROCES_idx_TABLE_TO_PROCES_GROUPED_VIEW` as tpvg
  75. where tpvg.`ID_PROCES` in({$sqlIdProcesListSql})
  76. group by tpvg.`ID_TABLE`
  77. ");
  78. }
  79. DB::getPDO()->execSql("
  80. update `{$this->_rootTableName}` c
  81. join `information_schema`.`TABLES` t on(t.TABLE_NAME = c.name and t.TABLE_SCHEMA = '{$dbName}')
  82. set c.ROOT_TABLE_NAME = t.TABLE_NAME
  83. where c.ID_USER = {$this->idUser}
  84. and c.db = {$idDatabase}
  85. {$sqlWhereAndIdProces}
  86. ");
  87. }
  88. public function getUsedUserProcesIdsSql() {
  89. if ($this->idProcesFilter > 0) {
  90. return "
  91. select i.`ID_PROCES`
  92. from `CRM_PROCES_idx` i
  93. where i.`idx_MAIN_PROCES_INIT_ID`='{$this->idProcesFilter}'
  94. ";
  95. }
  96. $idUserGroupList = $this->getUsedUserGroupIds();
  97. if (empty($idUserGroupList)) return null;
  98. $sqlIdUserGroupList = implode(",", $idUserGroupList);
  99. return "
  100. select gi.`ID_PROCES`
  101. from `CRM_PROCES_idx_GROUP_to_PROCES` gi
  102. where gi.`ID_GROUP` in({$sqlIdUserGroupList})
  103. ";
  104. }
  105. public function getUsedUserGroupIds() {
  106. // $idUserGroupList = User::getGroupsIds();
  107. // TODO: acl filtr by group ids
  108. return array_keys(UsersHelper::getGroupByUser($this->idUser));
  109. }
  110. public function getTotal($params = []) {
  111. $sqlParsedWhere = $this->_parseSqlWhere($params);
  112. $sqlWhere = " t.ID_USER = {$this->idUser} " .
  113. (($sqlParsedWhere) ? " and " . $sqlParsedWhere : "") .
  114. (($this->idProcesFilter > 0) ? " and t.ID_PROCES = {$this->idProcesFilter} " : " and t.ID_PROCES is NULL ")
  115. ;
  116. return DB::getPDO()->fetchValue("
  117. select count(1) as total
  118. from `{$this->_rootTableName}` t
  119. where {$sqlWhere}
  120. ");
  121. }
  122. function _parseSqlWhere($params = []) {
  123. $sqlWhereAnd = array();
  124. foreach ($params as $k => $v) {
  125. if (strlen($k) > 3 && substr($k, 0, 2) == 'f_') {
  126. DBG::log("TODO: Not implemented filter 'f_' for '{$k}' = '{$v}'");
  127. // //$v = trim($v, '% ');
  128. // //$sqlWhereAnd[] = "t.`" . substr($k, 2) . "` like '%" . DB::_($v) . "%'";
  129. // $fldName = substr($k, 2);
  130. // if ($this->isGeomField($fldName)) {
  131. // $sqlFilter = $this->_sqlValueForGeomField($fldName, $v, 't');
  132. // if ($sqlFilter) $sqlWhereAnd[] = $sqlFilter;
  133. // continue;
  134. // }
  135. // if ($this->isCsvNumericField($fldName)) {
  136. // $sqlFilter = $this->_sqlValueForCsvNumericField($fldName, $v, 't');
  137. // if ($sqlFilter) $sqlWhereAnd[] = $sqlFilter;
  138. // continue;
  139. // }
  140. // if (substr($v, 0, 1) == '=') {
  141. // $v = $this->getDB()->_(substr($v, 1));
  142. // if (strlen($v)) $sqlWhereAnd[] = "t.`{$fldName}`='{$v}'";
  143. // }
  144. // else if ($v == '!NULL' || $v == 'IS NOT NULL') {
  145. // $sqlWhereAnd[] = "t.`{$fldName}` is not null";
  146. // }
  147. // else if (substr($v, 0, 1) == '!') {
  148. // $v = $this->getDB()->_(substr($v, 1));
  149. // if (strlen($v)) $sqlWhereAnd[] = "t.`{$fldName}` not like '{$v}'";
  150. // }
  151. // else if (substr($v, 0, 2) == '<=') {
  152. // $v = $this->getDB()->_(substr($v, 2));
  153. // if (strlen($v)) $sqlWhereAnd[] = "t.`{$fldName}`<='{$v}'";
  154. // }
  155. // else if (substr($v, 0, 2) == '>=') {
  156. // $v = $this->getDB()->_(substr($v, 2));
  157. // if (strlen($v)) $sqlWhereAnd[] = "t.`{$fldName}`>='{$v}'";
  158. // }
  159. // else if (substr($v, 0, 1) == '<') {
  160. // $v = $this->getDB()->_(substr($v, 1));
  161. // if (strlen($v)) $sqlWhereAnd[] = "t.`{$fldName}`<'{$v}'";
  162. // }
  163. // else if (substr($v, 0, 1) == '>') {
  164. // $v = $this->getDB()->_(substr($v, 1));
  165. // if (strlen($v)) $sqlWhereAnd[] = "t.`{$fldName}`>'{$v}'";
  166. // }
  167. // else if (false !== strpos($v, '%')) {
  168. // $sqlWhereAnd[] = "t.`{$fldName}` like '{$v}'";
  169. // }
  170. // else if ($this->isColTypeNumber($fldName)) {
  171. // $v = $this->getDB()->_($v);
  172. // $sqlWhereAnd[] = "t.`{$fldName}`='{$v}'";
  173. // }
  174. // else {
  175. // $queryWhereBuilder = new SqlQueryWhereBuilder();
  176. // $searchWords = $queryWhereBuilder->splitQueryToWords($v);
  177. // $sqlWhereWords = array();
  178. // if (!empty($searchWords)) {
  179. // foreach ($searchWords as $word) {
  180. // $sqlWord = $this->getDB()->_($word);
  181. // $sqlWhereWords[] = "t.`{$fldName}` like '%{$sqlWord}%'";
  182. // }
  183. // }
  184. // if (!empty($searchWords)) {
  185. // $sqlWhereAnd[] = "(" . implode(" and ", $sqlWhereWords) . ")";
  186. // }
  187. // }
  188. }
  189. else if (strlen($k) > 4 && substr($k, 0, 3) == 'sf_') {
  190. DBG::log("TODO: Not implemented special filter 'sf_' for '{$k}' = '{$v}'");
  191. // $sqlFltr = $this->_parseSpecialFilter(substr($k, 3), $v);
  192. // if (!empty($sqlFltr)) {
  193. // $sqlWhereAnd[] = $sqlFltr;
  194. // }
  195. }
  196. else if ('ogc:Filter' == $k) {
  197. DBG::log($v, 'string', "TODO: Not implemented ogc:Filter filter");
  198. $sqlFltr = $this->_parseOgcFilter($v);
  199. if (!empty($sqlFltr)) {
  200. $sqlWhereAnd[] = $sqlFltr;
  201. }
  202. }
  203. else if ('primaryKey' == $k) {
  204. DBG::log("DBG: primaryKey filter '{$v}'");
  205. if (!empty($v)) {
  206. $primaryKeyField = $this->getPrimaryKeyField();
  207. $pdo = DB::getPDO();
  208. $sqlWhereAnd[] = "t." . $pdo->identifierQuote($primaryKeyField) . " = " . $pdo->quote($v);
  209. }
  210. }
  211. }
  212. return (!empty($sqlWhereAnd)) ? implode(" and ", $sqlWhereAnd) : "";
  213. }
  214. public function getItems($params = []) {
  215. $sqlIdProces = ($this->idProcesFilter > 0) ? $this->idProcesFilter : 'NULL';
  216. $cols = [];
  217. $cols[] = [ 'ID_TABLE', "t.ID_TABLE" ];
  218. $cols[] = [ 'ID_USER', "'{$this->idUser}'" ];
  219. $cols[] = [ 'ID_PROCES', "'{$sqlIdProces}'" ];
  220. $cols[] = [ 'db', "t.db" ];
  221. $cols[] = [ 'name', "t.name" ];
  222. $cols[] = [ 'label', "t.label" ];
  223. $cols[] = [ 'opis', "t.opis" ];
  224. $cols[] = [ '_rootTableName', "t._rootTableName" ];
  225. $cols[] = [ 'namespace', "(select o.namespace from `CRM_#CACHE_ACL_OBJECT` o where o.idZasob = t.ID_TABLE)" ];
  226. $colNameList = array_map(function ($x) { return $x[0]; }, $cols);
  227. $filterCols = V::get('cols', [], $params);
  228. $filterCols = array_filter($filterCols, function ($col) use ($colNameList) {
  229. return in_array($col, $colNameList);
  230. });
  231. DBG::log($filterCols, 'array', "DBG:\$filterCols");
  232. if (!empty($filterCols) && !in_array($this->getPrimaryKeyField(), $filterCols)) {
  233. $filterCols[] = $this->getPrimaryKeyField();
  234. }
  235. $sqlListCols = array_reduce($cols, function ($ret, $col) use ($filterCols) {
  236. if (!empty($filterCols) && !in_array($col[0], $filterCols)) return $ret;
  237. $ret[] = "{$col[1]} as `{$col[0]}`";
  238. return $ret;
  239. }, []);
  240. DBG::log($sqlListCols, 'array', "DBG:\$sqlListCols");
  241. $sqlCols = implode("\n, ", $sqlListCols);
  242. DBG::log($sqlCols, 'select', "DBG:\$sqlCols");
  243. $sqlOrderBy = "";
  244. $sqlLimitOffset = "";
  245. $currSortCol = V::get('order_by', 'ID', $params);
  246. $currSortFlip = strtolower(V::get('order_dir', 'desc', $params));
  247. // TODO: validate $currSortCol is in field list
  248. // TODO: validate $currSortFlip ('asc' or 'desc')
  249. $aliasMap = array();
  250. foreach ($this->_simpleSchema['root'] as $key => $field) {
  251. if ('@' === substr($key, 0, 1)) continue;
  252. $aliasMap[ $key ] = (!empty($field['@alias'])) ? $field['@alias'] : $key;
  253. }
  254. // TODO: if (!array_key_exists($currSortCol, $aliasMap)) throw new Exception("field name not allowed to sort");
  255. $currSortCol = (array_key_exists($currSortCol, $aliasMap)) ? $aliasMap[$currSortCol] : null;
  256. if (!empty($currSortCol) && ('asc' == $currSortFlip || 'desc' == $currSortFlip)) {
  257. $sqlOrderBy = "order by t.`{$currSortCol}` {$currSortFlip}";
  258. }
  259. $limit = V::get('limit', 0, $params);
  260. $limit = ($limit < 0) ? 0 : $limit;
  261. $offset = V::get('limitstart', 0, $params);
  262. $offset = ($offset < 0) ? 0 : $offset;
  263. if ($limit > 0) $sqlLimitOffset = "limit {$limit} offset {$offset}";
  264. // $sql = "
  265. // select tpvg.`ID_TABLE`
  266. // , tpvg.`ID_DATABASE` as `db`
  267. // , tpvg.`TABLE_NAME` as `name`
  268. // , tpvg.`TABLE_LABEL` as `label`
  269. // , tpvg.`TABLE_DESCRIPTION` as `opis`
  270. // from `CRM_PROCES_idx_TABLE_TO_PROCES_GROUPED_VIEW` as tpvg
  271. // where tpvg.`ID_PROCES` in({$sqlIdProcesListSql})
  272. // group by tpvg.`ID_TABLE`
  273. // ";
  274. // DBG::logAuth($sql, "_fetchPerms sql");
  275. // $sql = "
  276. // select c.ID_TABLE
  277. // , c.db
  278. // , c.name
  279. // , c.label
  280. // , c.opis
  281. // , c.ROOT_TABLE_NAME as _rootTableName
  282. // from `CRM_AUTH_#CACHE_ACL_OBJECT` as c
  283. // where c.ID_USER = {$idUser}
  284. // {$sqlWhereAndIdProces}
  285. // ";
  286. // $userAccessForTables = DB::getPDO()->fetchAllByKey($sql, 'ID_TABLE');
  287. $sqlParsedWhere = $this->_parseSqlWhere($params);
  288. $sqlWhere = ($sqlParsedWhere) ? $sqlParsedWhere : "1=1";
  289. $subSqlWhere = "c.ID_USER = {$this->idUser}" .
  290. (($this->idProcesFilter > 0) ? " and c.ID_PROCES = {$this->idProcesFilter} " : " and c.ID_PROCES is NULL ")
  291. ;
  292. $items = DB::getPDO()->fetchAllByKey("
  293. select {$sqlCols}
  294. from (
  295. select c.ID_TABLE
  296. , c.db
  297. , c.name
  298. , c.label
  299. , c.opis
  300. , c.ROOT_TABLE_NAME as _rootTableName
  301. from `{$this->_rootTableName}` as c
  302. where {$subSqlWhere}
  303. ) as t
  304. where {$sqlWhere}
  305. {$sqlOrderBy}
  306. {$sqlLimitOffset}
  307. ", 'ID_TABLE');
  308. // array_walk($items, function (&$item, $key) {
  309. // $item['link_uruchom_filtr_procesu'] = Request::getPathUri() . "index.php?FUNCTION_INIT=MENU_SELECT_PROCES&_action=setPermsByProces&id_proces={$item['ID']}";
  310. // });
  311. return $items;
  312. }
  313. }