AclReinstall.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <?php
  2. Lib::loadClass('RouteBase');
  3. Lib::loadClass('Router');
  4. Lib::loadClass('Response');
  5. Lib::loadClass('UI');
  6. Lib::loadClass('SchemaFactory');
  7. class Route_Storage_AclReinstall extends RouteBase {
  8. public function handleAuth() {
  9. if (!User::logged()) {
  10. User::authByRequest();
  11. }
  12. }
  13. public function defaultAction() {
  14. UI::gora();
  15. UI::startContainer();
  16. try {
  17. $namespace = V::get('namespace', '', $_GET);
  18. if (empty($namespace)) throw new Exception("Missing param namespace");
  19. echo UI::h('h3', [], $namespace);
  20. echo UI::h('p', [], [
  21. UI::h('a', [
  22. 'href' => Router::getRoute('Storage_AclStruct')->getLink('', [ 'namespace' => $namespace ]),
  23. 'class' => "btn btn-md btn-link",
  24. ], "<i class=\"glyphicon glyphicon-arrow-left\"></i> Wróć do struktury"),
  25. " | ",
  26. UI::h('a', [
  27. 'href' => $this->getLink('viewXsdSource', [ 'namespace' => $namespace ]),
  28. 'class' => "btn btn-md btn-link",
  29. 'target' => "_blank",
  30. ], "Otwórz plik xsd (źródłowy)"),
  31. ]);
  32. if ('reinstall' == V::get('_postTask', '', $_POST)) {
  33. Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
  34. $objFieldAcl = new Schema_SystemObjectFieldStorageAcl();
  35. $objFieldAcl->updateCache($namespace);
  36. DBG::nicePrint([
  37. 'idInstance' => ACL::getInstanceId($namespace),
  38. 'rootInstance' => ACL::getRootNamespace($namespace),
  39. 'conf' => ACL::fetchInstanceConfig($namespace),
  40. 'table' => ACL::getInstanceTable($namespace),
  41. ], "dbg");
  42. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  43. $childRefList = ACL::getChildRefFullList($namespace);
  44. DBG::nicePrint($childRefList, '$childRefList');
  45. DBG::nicePrint($item, '$item');
  46. $activeFields = array_filter($item['field'], function ($field) {
  47. return ($field['isActive'] > 0);
  48. });
  49. $fieldNsList = array_map(function ($field) {
  50. return $field['fieldNamespace'];
  51. }, $activeFields);
  52. DBG::nicePrint($fieldNsList, '$fieldNsList');
  53. if ('AntAcl' === $item['_type']) {
  54. foreach ($childRefList as $childRef) { // [ namespace, A_STATUS ]
  55. if ($childRef['A_STATUS'] !== 'DELETED' && !in_array($childRef['namespace'], $fieldNsList)) {
  56. UI::alert('danger', "remove ref config for '{$childRef['namespace']}' ...");
  57. if (!$childRef['ID']) throw new Exception("Missing ref config ID");
  58. DB::getPDO()->update('CRM_REF_CONFIG', 'ID', $childRef['ID'], [
  59. 'A_STATUS' => 'DELETED',
  60. 'A_LAST_ACTION_DATE' => 'NOW()',
  61. ]);
  62. }
  63. else if ($childRef['A_STATUS'] !== 'DELETED' && in_array($childRef['namespace'], $fieldNsList)) {
  64. UI::alert('info', "ref config for '{$childRef['namespace']}' active - OK");
  65. }
  66. else if ($childRef['A_STATUS'] === 'DELETED' && in_array($childRef['namespace'], $fieldNsList)) {
  67. UI::alert('warning', "activate ref config for '{$childRef['namespace']}' ...");
  68. if (!$childRef['ID']) throw new Exception("Missing ref config ID");
  69. DB::getPDO()->update('CRM_REF_CONFIG', 'ID', $childRef['ID'], [
  70. 'A_STATUS' => 'NORMAL',
  71. 'A_LAST_ACTION_DATE' => 'NOW()',
  72. ]);
  73. }
  74. else if ($childRef['A_STATUS'] === 'DELETED' && !in_array($childRef['namespace'], $fieldNsList)) {
  75. UI::alert('info', "ref config for '{$childRef['namespace']}' removed - OK");
  76. }
  77. else {
  78. UI::alert('danger', "Not implemented action for '{$childRef['namespace']}'");
  79. }
  80. }
  81. // TODO: create missing refConfig - field is not in $childRefList
  82. }
  83. {
  84. if ('AntAcl' === $item['_type']) {
  85. $dbName = DB::getPDO()->getDatabaseName();
  86. $sqlFunBody = ACL::generateIsInstanceFunctionBody($namespace, $item);
  87. DBG::nicePrint($sqlFunBody, "\$sqlFunBody");
  88. $idInstance = ACL::getInstanceId($namespace);
  89. DB::getPDO()->execSql(" DROP FUNCTION IF EXISTS `{$dbName}`.`isInstance_{$idInstance}` ");
  90. // CREATE
  91. // [DEFINER = { user | CURRENT_USER }]
  92. // FUNCTION sp_name ([func_parameter[,...]])
  93. // RETURNS type
  94. // [characteristic ...] routine_body
  95. DB::getPDO()->execSql("
  96. CREATE DEFINER=`root`@`localhost`
  97. FUNCTION `{$dbName}`.`isInstance_{$idInstance}` ( pk INT(11) )
  98. RETURNS TINYINT(1)
  99. {$sqlFunBody}
  100. ");
  101. }
  102. }
  103. return;
  104. }
  105. echo UI::hButtonPost("Reinstall", [
  106. 'data' => [
  107. '_postTask' => 'reinstall'
  108. ],
  109. 'class' => 'btn btn-md btn-danger',
  110. 'title' => "Reinstall structure"
  111. ]);
  112. echo '<hr>';
  113. try {
  114. $this->printReinstallPreview($namespace);
  115. } catch (Exception $e) {
  116. DBG::log($e);
  117. UI::alert('danger', $e->getMessage());
  118. }
  119. } catch (Exception $e) {
  120. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  121. DBG::log($e);
  122. }
  123. UI::endContainer();
  124. UI::dol();
  125. }
  126. public function printReinstallPreview($namespace) {
  127. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => "*,field" ]);
  128. DBG::log($objectItem, 'array', '$objectItem preview');
  129. switch ($objectItem['_type']) {
  130. case 'AntAcl': $this->printReinstallAntAclPreview($objectItem); break;
  131. case 'TableAcl': $this->printReinstallTableAclPreview($objectItem); break;
  132. case 'StorageAcl': $this->printReinstallStorageAclPreview($objectItem); break;
  133. default: throw new Exception("TODO: Not Implemented type '{$objectItem['_type']}'");
  134. }
  135. }
  136. public function printReinstallAntAclPreview($item) {
  137. Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
  138. $antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($item['typeName']);
  139. if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
  140. Lib::loadClass('XML');
  141. $xsdType = XML::getXsdTypeFromXsdSchema("{$antAclPath}/{$item['name']}.xsd", $namespace = $item['namespace'], $name = $item['name']);
  142. DBG::nicePrint($item, '$item');
  143. DBG::nicePrint($xsdType, '$xsdType');
  144. echo '<hr>';
  145. echo UI::h('h3', [], "Lista zmian:");
  146. echo ($item['primaryKey'] != $xsdType['primaryKey'])
  147. ? UI::h('p', [ 'style' => "" ], "@primaryKey - zmiana z '{$item['primaryKey']}' na '{$xsdType['primaryKey']}'")
  148. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "@primaryKey - bez zmian");
  149. if (empty($xsdType['struct'])) throw new Exception("Field list not found for '{$item['namespace']}'");
  150. foreach ($xsdType['struct'] as $fieldName => $x) {
  151. $listEnum = [];
  152. if (!empty($x['restrictions']['enumeration'])) {
  153. $listEnum = $x['restrictions']['enumeration'];
  154. unset($x['restrictions']['enumeration']);
  155. }
  156. if (!empty($listEnum)) {
  157. DBG::log($listEnum, 'array', "\$listEnum for field '{$fieldName}'");
  158. }
  159. }
  160. $old = [
  161. 'fields' => array_map(function ($field) { return $field['fieldNamespace']; }, $item['field']),
  162. ];
  163. $new = [
  164. 'fields' => array_keys($xsdType['struct']),
  165. ];
  166. sort($old['fields']);
  167. sort($new['fields']);
  168. $diffFieldsToCreate = array_diff($new['fields'], $old['fields']);
  169. $diffFieldsToRemove = array_diff($old['fields'], $new['fields']);
  170. $sameFields = array_intersect($new['fields'], $old['fields']);
  171. echo (!empty($diffFieldsToCreate))
  172. ? UI::h('details', [ 'open' => "open" ], [
  173. UI::h('summary', [], "Pola do dodania (".count($diffFieldsToCreate)."):"),
  174. UI::h('ul', [], array_map(function ($fieldName) {
  175. return UI::h('li', [], $fieldName);
  176. }, $diffFieldsToCreate)),
  177. ])
  178. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do dodania");
  179. echo (!empty($diffFieldsToRemove))
  180. ? UI::h('details', [ 'open' => "open", 'style' => "margin:4px 0; color:#8a6d3b; background-color:#fcf8e3; border:1px solid #faebcc;" ], [
  181. UI::h('summary', [ 'style' => "padding:4px; outline:none; cursor:pointer" ], "Pola do usunięcia (".count($diffFieldsToRemove)."):"),
  182. UI::h('ul', [], array_map(function ($fieldName) {
  183. return UI::h('li', [], $fieldName);
  184. }, $diffFieldsToRemove)),
  185. ])
  186. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do usunięcia");
  187. foreach ($sameFields as $fieldName) {
  188. // UI::alert('warning', "TODO: is field changed? '{$fieldName}'");
  189. $oldField = array_filter($item['field'], function ($field) use ($fieldName) { return ( $fieldName === $field['fieldNamespace'] ); });
  190. $oldField = ($oldField) ? reset($oldField) : null;
  191. // DBG::nicePrint($oldField, "\$oldField '$fieldName'");
  192. $newField = $xsdType['struct'][$fieldName];
  193. // DBG::nicePrint($newField, "\$newField '$fieldName'");
  194. $fieldDiff = [];
  195. if ($newField['type'] !== $oldField['xsdType']) $fieldDiff[] = 'xsdType';
  196. if ($newField['minOccurs'] != $oldField['minOccurs']) $fieldDiff[] = 'minOccurs';
  197. if ($newField['maxOccurs'] != $oldField['maxOccurs']) $fieldDiff[] = 'maxOccurs';
  198. if (json_encode($newField['restrictions']) !== $oldField['xsdRestrictions']) $fieldDiff[] = 'xsdRestrictions';
  199. if (json_encode($newField['appInfo']) !== $oldField['appInfo']) $fieldDiff[] = 'appInfo';
  200. echo (!empty($fieldDiff))
  201. ? UI::h('p', [ 'style' => "" ], "Pole '{$fieldName}' - zmiany: " . implode(", ", $fieldDiff))
  202. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Pole '{$fieldName}' - bez zmian");
  203. }
  204. }
  205. public function printReinstallTableAclPreview($item) {
  206. throw new Exception("TODO: Podgląd zmian dla tabeli {$item['namespace']} ...");
  207. }
  208. public function printReinstallStorageAclPreview($item) {
  209. DBG::nicePrint($item, '$item');
  210. $acl = SchemaFactory::loadDefaultObject($item['name']);
  211. DBG::nicePrint($acl, '$acl');
  212. $xsdType = [
  213. 'primaryKey' => $acl->getPrimaryKeyField(),
  214. 'struct' => $acl->getFieldsWithXsdTypes()
  215. ];
  216. DBG::nicePrint($xsdType, '$xsdType');
  217. echo '<hr>';
  218. echo UI::h('h3', [], "Lista zmian:");
  219. echo ($item['primaryKey'] != $xsdType['primaryKey'])
  220. ? UI::h('p', [ 'style' => "" ], "@primaryKey - zmiana z '{$item['primaryKey']}' na '{$xsdType['primaryKey']}'")
  221. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "@primaryKey - bez zmian");
  222. if (empty($xsdType['struct'])) throw new Exception("Field list not found for '{$item['namespace']}'");
  223. foreach ($xsdType['struct'] as $fieldName => $x) {
  224. $listEnum = [];
  225. if (!empty($x['restrictions']['enumeration'])) {
  226. $listEnum = $x['restrictions']['enumeration'];
  227. unset($x['restrictions']['enumeration']);
  228. }
  229. if (!empty($listEnum)) {
  230. DBG::log($listEnum, 'array', "\$listEnum for field '{$fieldName}'");
  231. }
  232. }
  233. $old = [
  234. 'fields' => array_map(function ($field) { return $field['fieldNamespace']; }, $item['field']),
  235. ];
  236. $new = [
  237. 'fields' => array_keys($xsdType['struct']),
  238. ];
  239. sort($old['fields']);
  240. sort($new['fields']);
  241. $diffFieldsToCreate = array_diff($new['fields'], $old['fields']);
  242. $diffFieldsToRemove = array_diff($old['fields'], $new['fields']);
  243. $sameFields = array_intersect($new['fields'], $old['fields']);
  244. echo (!empty($diffFieldsToCreate))
  245. ? UI::h('details', [ 'open' => "open" ], [
  246. UI::h('summary', [], "Pola do dodania (".count($diffFieldsToCreate)."):"),
  247. UI::h('ul', [], array_map(function ($fieldName) {
  248. return UI::h('li', [], $fieldName);
  249. }, $diffFieldsToCreate)),
  250. ])
  251. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do dodania");
  252. echo (!empty($diffFieldsToRemove))
  253. ? UI::h('details', [ 'open' => "open", 'style' => "margin:4px 0; color:#8a6d3b; background-color:#fcf8e3; border:1px solid #faebcc;" ], [
  254. UI::h('summary', [ 'style' => "padding:4px; outline:none; cursor:pointer" ], "Pola do usunięcia (".count($diffFieldsToRemove)."):"),
  255. UI::h('ul', [], array_map(function ($fieldName) {
  256. return UI::h('li', [], $fieldName);
  257. }, $diffFieldsToRemove)),
  258. ])
  259. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do usunięcia");
  260. foreach ($sameFields as $fieldName) {
  261. // UI::alert('warning', "TODO: is field changed? '{$fieldName}'");
  262. $oldField = array_filter($item['field'], function ($field) use ($fieldName) { return ( $fieldName === $field['fieldNamespace'] ); });
  263. $oldField = ($oldField) ? reset($oldField) : null;
  264. // DBG::nicePrint($oldField, "\$oldField '$fieldName'");
  265. $newField = $xsdType['struct'][$fieldName];
  266. // DBG::nicePrint($newField, "\$newField '$fieldName'");
  267. $fieldDiff = [];
  268. if ($newField['type'] !== $oldField['xsdType']) $fieldDiff[] = 'xsdType';
  269. if ($newField['minOccurs'] != $oldField['minOccurs']) $fieldDiff[] = 'minOccurs';
  270. if ($newField['maxOccurs'] != $oldField['maxOccurs']) $fieldDiff[] = 'maxOccurs';
  271. if (json_encode($newField['restrictions']) !== $oldField['xsdRestrictions']) $fieldDiff[] = 'xsdRestrictions';
  272. if (json_encode($newField['appInfo']) !== $oldField['appInfo']) $fieldDiff[] = 'appInfo';
  273. echo (!empty($fieldDiff))
  274. ? UI::h('p', [ 'style' => "" ], "Pole '{$fieldName}' - zmiany: " . implode(", ", $fieldDiff))
  275. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Pole '{$fieldName}' - bez zmian");
  276. }
  277. }
  278. public function viewXsdSourceAction() {
  279. try {
  280. $namespace = V::get('namespace', '', $_GET);
  281. if (empty($namespace)) throw new Exception("Missing param namespace");
  282. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => "*,field" ]);
  283. switch ($objectItem['_type']) {
  284. case 'AntAcl': $this->viewXsdSource($objectItem); break;
  285. // case 'TableAcl': $this->viewXsdSource($objectItem); break;
  286. default: throw new Exception("TODO: Not Implemented type '{$objectItem['_type']}'");
  287. }
  288. } catch (Exception $e) {
  289. DBG::log($e);
  290. echo "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage();
  291. }
  292. }
  293. function viewXsdSource($objectItem) {
  294. if (empty($objectItem)) throw new Exception("Missing objectItem in viewXsdSource");
  295. DBG::log($objectItem, "viewXsdSource \$objectItem");
  296. Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
  297. $antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($objectItem['typeName']);
  298. if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
  299. DBG::log(str_replace(APP_PATH_ROOT, '~', $antAclPath), "viewXsdSource \$antAclPath");
  300. $xsdFile = "{$antAclPath}/{$objectItem['name']}.xsd";
  301. if (!file_exists($xsdFile)) throw new Exception("Xsd file not exists");
  302. DBG::log(str_replace(APP_PATH_ROOT, '~', $xsdFile), "viewXsdSource \$xsdFile");
  303. header('Content-Type: application/xml; charset=utf-8');
  304. $fd = fopen($xsdFile, 'r');
  305. fpassthru($fd);
  306. exit;
  307. }
  308. }