AclStruct.php 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  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_AclStruct extends RouteBase {
  8. public function handleAuth() {
  9. if (!User::logged()) {
  10. User::authByRequest();
  11. }
  12. }
  13. public function defaultAction() {
  14. UI::gora();
  15. UI::menu();
  16. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  17. UI::startTag('div', [ 'class' => 'container-fluid' ]);
  18. try {
  19. $namespace = V::get('namespace', '', $_GET);
  20. if (empty($namespace)) throw new Exception("Missing param namespace");
  21. // [idZasob] => 25872
  22. // [idDatabase] => 36
  23. // [namespace] => default_db/CRM_PROCES/CRM_PROCES
  24. // [_rootTableName] => CRM_PROCES
  25. // [_type] => AntAcl
  26. // [hasStruct] => 1
  27. // [isStructInstalled] => 1
  28. // [isObjectActive] => 1
  29. // [description] =>
  30. // [name] => CRM_PROCES
  31. // [nsPrefix] => default_db__x3A__CRM_PROCES
  32. // [typeName] => default_db__x3A__CRM_PROCES:CRM_PROCES
  33. // [reinstallLink] => https://biuro.biall-net.pl/dev-pl/se-master/index.php?_route=Storage&_task=objectReinstall&namespace=default_db/CRM_PROCES/CRM_PROCES
  34. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  35. switch ($item['_type']) {
  36. case 'TableAcl': $this->tableStructView($item, $item['name'], $item['idDatabase']); break;
  37. case 'AntAcl': $this->objectStructView($item); break;
  38. default: throw new Exception("Not implemented type"); break;
  39. }
  40. } catch (Exception $e) {
  41. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  42. DBG::log($e);
  43. }
  44. UI::endTag('div'); // .container-fluid
  45. UI::dol();
  46. }
  47. public function tableStructAction() {
  48. UI::gora();
  49. UI::menu();
  50. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  51. try {
  52. $idStorage = V::get('idStorage', 0, $_REQUEST, 'int');
  53. if (empty($idStorage)) throw new Exception("Missing id storage");
  54. $storageList = Router::getRoute('Storage')->getStorageList();
  55. if (empty($storageList)) throw new Exception("No storage defined");
  56. if (!array_key_exists($idStorage, $storageList)) throw new Exception("Storage not exists");
  57. $tblName = V::get('table', '', $_REQUEST, 'word');
  58. if (empty($tblName)) throw new Exception("No table name");
  59. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  60. $this->tableStructView($item, $tblName, $idStorage);
  61. } catch (Exception $e) {
  62. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  63. }
  64. UI::dol();
  65. }
  66. public function objectStructureAction() { // objectStructAction
  67. UI::gora();
  68. UI::menu();
  69. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  70. UI::startTag('div', [ 'class' => 'container-fluid' ]);
  71. try {
  72. $namespace = V::get('namespace', '', $_GET);
  73. if (empty($namespace)) throw new Exception("Missing param namespace");
  74. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  75. $this->objectStructView($item);
  76. } catch (Exception $e) {
  77. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  78. DBG::log($e);
  79. }
  80. UI::endTag('div'); // .container-fluid
  81. UI::dol();
  82. }
  83. public function tableStructView($item, $tblName, $idStorage) {
  84. $storagePdo = DB::getStorage($idStorage);
  85. $tblStruct = $storagePdo->getTableStruct($tblName);
  86. $idTable = Router::getRoute('Storage')->fetchTableId($idStorage, $tblName);
  87. if ($idTable <= 0) {
  88. UI::alert('warning', "Zasob tabela '{$tblName}' nie istnieje");// TODO: add p5UI btn
  89. DBG::table("tblStruct", $tblStruct, __CLASS__, __FUNCTION__, __LINE__);
  90. throw new Exception("Zasob tabela '{$tblName}' nie istnieje");
  91. }
  92. $cellZasobList = array();
  93. foreach (DB::getPDO()->fetchAllByKey("
  94. select z.ID, z.`DESC`, z.`TYPE` as ZASOB_TYPE, z.A_STATUS, z.SORT_PRIO
  95. from CRM_LISTA_ZASOBOW z
  96. where z.PARENT_ID = '{$idTable}'
  97. ", $key = 'DESC') as $ind => $row) {
  98. $cellZasobList[strtolower($ind)] = $row;
  99. }
  100. $emptyItem = array();
  101. $emptyItem['sort'] = null;
  102. $emptyItem['name'] = '';
  103. $emptyItem['id_zasob'] = '';
  104. $emptyItem['zasob_type'] = '';
  105. $emptyItem['uwagi'] = '';
  106. $emptyItem['type'] = '';
  107. $emptyItem['is_nullable'] = '';
  108. $emptyItem['default_value'] = '';
  109. $emptyItem['default_is_null'] = '';
  110. $emptyItem['max_length'] = '';
  111. $emptyItem['num_precision'] = '';
  112. $emptyItem['num_scale'] = '';
  113. $emptyItem['char_encoding'] = '';
  114. $emptyItem['char_collation'] = '';
  115. $emptyItem['extra'] = '';
  116. $emptyItem['raw_storage_type'] = '';
  117. $tableList = array();
  118. foreach ($tblStruct as $row) {
  119. $cellName = $row['name'];
  120. $tblItem = V::cloneArray($emptyItem);
  121. $tblItem['name'] = $cellName;
  122. foreach ($row as $fldName => $fldVal) {
  123. if (array_key_exists($fldName, $tblItem)) $tblItem[$fldName] = $fldVal;
  124. }
  125. $tblItem['uwagi'] = '';
  126. $lowerCellName = strtolower($cellName);
  127. $tblZasob = V::get($lowerCellName, '', $cellZasobList);
  128. if ($tblZasob) {
  129. $cellZasobList[$lowerCellName]['_checked'] = true;
  130. $tblItem['id_zasob'] = $tblZasob['ID'];
  131. $tblItem['zasob_type'] = $tblZasob['ZASOB_TYPE'];
  132. $tblItem['sort'] = $tblZasob['SORT_PRIO'];
  133. } else {
  134. $tblItem['uwagi'] .= '!Zasob';//'TODO: ADD ZASOB';
  135. $ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addCellToZasoby', [ 'idStorage' => $idStorage, 'tblName' => $tblName, 'cellName' => $cellName]);
  136. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addCellToZasoby', { href: '{$ajaxAddZasobLink}' })";
  137. $tblItem['id_zasob'] = '<a onclick="'.$onClick.'" class="btn btn-xs btn-primary" href="#">TODO: ADD ZASOB</a>';
  138. }
  139. $tableList[] = $tblItem;
  140. }
  141. foreach ($cellZasobList as $cellName => $row) {
  142. if ('URL_ACTION' == $row['ZASOB_TYPE']) continue;
  143. if (!$row['_checked']) {
  144. $tblItem = V::cloneArray($emptyItem);
  145. $tblItem['name'] = $cellName;
  146. $tblItem['id_zasob'] = $row['ID'];
  147. $tblItem['zasob_type'] = $row['ZASOB_TYPE'];
  148. $tblItem['uwagi'] = '!DB';//'TODO: nie istnieje w bazie danych';
  149. $tableList[] = $tblItem;
  150. }
  151. }
  152. { // sortBy
  153. $sortByArgName = 'sortBy';
  154. $sortByCol = V::get($sortByArgName, 'name', $_GET);
  155. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $_GET);
  156. if ('name' === $sortByCol) {
  157. usort($tableList, function($rowA, $rowB) {
  158. $a = $rowA['name']; $b = $rowB['name'];
  159. // if ('ID' == $a) return -1;
  160. // if ('ID' == $b) return 1;
  161. if ($a == $b) return 0;
  162. $a1 = substr($a, 0, 1); $b1 = substr($b, 0, 1);
  163. if (('_' == $a1 || '_' == $b1) && $a1 != $b1) {
  164. return ($a1 < $b1) ? 1 : -1;
  165. }
  166. return ($a < $b) ? -1 : 1;
  167. });
  168. }
  169. else if ('sort' === $sortByCol) {
  170. usort($tableList, function ($a, $b) use ($sortByDir) {
  171. if (null === $a['sort'] && null === $b['sort']) return 0;
  172. if (null === $a['sort'] && null != $b['sort']) return 1;
  173. if (null !== $a['sort'] && null === $b['sort']) return -1;
  174. if ($a['sort'] > $b['sort']) return 'asc' === $sortByDir ? 1 : -1;
  175. if ($a['sort'] < $b['sort']) return 'asc' === $sortByDir ? -1 : 1;
  176. return 0;
  177. });
  178. }
  179. echo UI::h('style', [ 'type' => "text/css" ], "
  180. .ta-ordering { cursor:pointer }
  181. .ta-ordering-desc:after { content:\"\\e252\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  182. .ta-ordering-asc:after { content:\"\\e253\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  183. .ta-sortable-item { }
  184. .ta-sortable-item-handle { cursor:pointer }
  185. ");
  186. echo UI::h('script', [ 'src' => "static/URI.js" ]);
  187. echo UI::h('script', [], "
  188. function p5UI_table_sortBy_get(n, argName, colName, dir) {
  189. var newUri = URI(window.location.href).setQuery(argName, colName).setQuery(argName+'Dir', dir).build().toString();
  190. window.location.href = newUri
  191. }
  192. ");
  193. }
  194. UI::table([
  195. '__html_id' => 'struct_table',
  196. 'caption' => UI::h('span', [], [
  197. "Struktura tabeli {$tblName} [{$idTable}] ",
  198. UI::h('a', [
  199. 'href' => "index.php?_route=ViewTableAjax&namespace=default_db/{$tblName}",
  200. 'class' => "btn btn-md btn-link"
  201. ], "Przeglądaj tabelę"),
  202. UI::h('a', [
  203. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$idTable}&filtr_ids=%2B&filtr_ob=%2B",
  204. 'class' => "btn btn-md btn-link",
  205. 'title' => "Struktura aktualnie przeglądanej tabeli"
  206. ], "Zasoby"),
  207. UI::h('a', [
  208. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$idTable}",
  209. 'class' => "btn btn-md btn-link",
  210. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  211. ], "Procesy"),
  212. UI::h('a', [
  213. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => "default_db/{$tblName}" ]),
  214. 'class' => "btn btn-md btn-link",
  215. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  216. ], "Uprawnienia (analiza użycia)"),
  217. ]),
  218. 'cols_label' => [
  219. 'sort' => UI::h('nobr', [
  220. 'class' => "ta-ordering" . ('sort' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  221. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'sort', '" . ('sort' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  222. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  223. ], "sort"),
  224. 'name' => UI::h('nobr', [
  225. 'class' => "ta-ordering" . ('name' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  226. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'name', '" . ('name' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  227. 'title' => "Sortuj wg nazwy",
  228. ], "namespace"),
  229. ],
  230. 'cols' => array_keys($emptyItem),
  231. 'rows' => array_map(function ($item) use ($sortByCol) {
  232. if ('sort' === $sortByCol && null !== $item['sort'] && !empty($item['id_zasob'])) {
  233. $item['@class'] = "ta-sortable-item";
  234. $item['@class[sort]'] = "ta-sortable-item-handle";
  235. $item['@data']['sort_prio'] = $item['sort'];
  236. $item['@data']['id_zasob'] = $item['id_zasob'];
  237. $item['sort'] = ":: {$item['sort']}";
  238. }
  239. return $item;
  240. }, $tableList),
  241. ]);
  242. echo UI::h('script', [], "
  243. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:click', function(e, n, payload) {
  244. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:click', n, payload);
  245. });
  246. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', function(e, n, payload) {
  247. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', n, payload);
  248. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  249. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  250. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  251. jQuery(n).parents('td').text(payload.body.id);
  252. jQuery(n).remove();
  253. }
  254. jQuery.notify(payload.msg, payload.type);
  255. });
  256. ");
  257. $ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addGeomEtykietaCells', [ 'idStorage' => $idStorage, 'tblName' => $tblName]);
  258. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addGeomEtykietaCells', { href: '{$ajaxAddZasobLink}' })";
  259. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj komórki etykiet", true);
  260. echo "<i>(<code>`etykieta_x`</code>, <code>`etykieta_y`</code>, <code>`etykieta_obrot`</code>)</i>";
  261. echo UI::h('script', [], "
  262. jQuery(document).on('p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', function(e, n, payload) {
  263. console.log('event p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', n, payload);
  264. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  265. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  266. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  267. jQuery(n).parents('td').text(payload.body.id);
  268. jQuery(n).remove();
  269. }
  270. jQuery.notify(payload.msg, payload.type);
  271. });
  272. ");
  273. $tableActions = array_filter($cellZasobList, function ($row) {
  274. return ('URL_ACTION' == $row['ZASOB_TYPE']);
  275. });
  276. UI::table([
  277. 'caption' => "tableActions",
  278. // 'cols' => array_keys($emptyItem),
  279. 'rows' => array_map(function ($item) {
  280. $sqlIdAction = DB::getPDO()->quote($item['ID'], PDO::PARAM_INT);
  281. $args = DB::getPDO()->fetchAll("
  282. select z.`DESC`
  283. , a.ID as ALIAS_ID, a.`DESC` as ALIAS_DESC, a.OPIS as ALIAS_OPIS
  284. from CRM_LISTA_ZASOBOW z
  285. left join CRM_LISTA_ZASOBOW a on(a.ID = z.ALIAS_ID)
  286. where z.PARENT_ID = {$sqlIdAction}
  287. and z.`TYPE` = 'PARAM_IN'
  288. ");
  289. $definitionArgs = DB::getPDO()->fetchAll("
  290. select p.ID, p.`DESC`
  291. from CRM_LISTA_ZASOBOW z
  292. join CRM_LISTA_ZASOBOW d on(d.ID = z.ALIAS_ID)
  293. left join CRM_LISTA_ZASOBOW p on(p.PARENT_ID = d.ID)
  294. where z.ID = {$sqlIdAction}
  295. and p.`TYPE` = 'PARAM_IN'
  296. ");
  297. $flatDefinitionArgs = implode(";", array_map(function ($arg) {
  298. return "{$arg['ID']}={$arg['DESC']}";
  299. }, $definitionArgs));
  300. return [
  301. 'label' => DB::getPDO()->fetchValue(" select z.OPIS from CRM_LISTA_ZASOBOW z where z.ID = {$sqlIdAction} ") . " " .
  302. UI::h('i', [
  303. 'class' => "glyphicon glyphicon-pencil",
  304. 'style' => "cursor:pointer",
  305. 'onClick' => "return Storage__tableStruct__editActionLabel(this, {$sqlIdAction})"], ''),
  306. 'args' => implode("<br>&", array_map(function ($item) {
  307. return (NULL === $item['ALIAS_ID'])
  308. ? $item['DESC']
  309. : "{$item['DESC']}=" . '{$row["' . $item['ALIAS_DESC'] . '"]}';// TODO: add rmParam btn
  310. }, $args)) . " " .
  311. UI::h('i', [
  312. 'class' => "glyphicon glyphicon-plus-sign",
  313. 'style' => "cursor:pointer",
  314. 'title' => "Dodaj PARAM_IN",
  315. 'onClick' => "return Storage__tableStruct__addParamAction(this, {$sqlIdAction}, '{$flatDefinitionArgs}')"], ''),
  316. // 'args_info' => '<pre>' . var_export($args, true) . '</pre>',
  317. 'ID' => $item['ID'],
  318. 'DESC' => $item['DESC'],
  319. 'A_STATUS' => $item['A_STATUS'],
  320. 'definition args' => implode("", array_map(function ($item) {
  321. return '<div style="white-space:nowrap">' . "[{$item['ID']}] {$item['DESC']}" . '</div>';
  322. }, $definitionArgs)),
  323. ];
  324. }, $tableActions)
  325. ]);
  326. echo UI::h('button', [
  327. 'onClick'=>"Storage__tableStruct__addAction()",
  328. 'class'=>"btn btn-xs btn-default"
  329. ], "Dodaj Akcję");
  330. echo UI::h('link', ['rel'=>"stylesheet", 'type'=>"text/css", 'href'=>"static/sweetalert2.min.css"]);
  331. echo UI::h('script', ['src'=>"static/sweetalert2.min.js"]);
  332. echo UI::h('style', [], "
  333. .swal2-radio.p5-swal-radio-as-list { text-align:left }
  334. .swal2-radio.p5-swal-radio-as-list > label { display:block; margin-left:20px }
  335. ");
  336. UI::inlineJS(__FILE__ . '.tableActions.js', [
  337. 'ID_STORAGE' => $idStorage,
  338. 'TABLE_NAME' => $tblName,
  339. 'FETCH_URL' => Router::getRoute('Storage')->getLink('fetchActionListAjax'),
  340. 'ADD_ACTION_URL' => Router::getRoute('Storage')->getLink('addActionAjax')
  341. ]);
  342. echo '<hr>';
  343. $ajaxAddBaseProcesLink = Router::getRoute('Storage')->getLink('addTableBaseProces', [ 'idStorage' => $idStorage, 'tblName' => $tblName ]);
  344. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addTableBaseProces', { href: '{$ajaxAddBaseProcesLink}' })";
  345. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj podstawowy proces dla tabeli '{$tblName}' - read only", true);
  346. echo UI::h('script', [], "
  347. jQuery(document).on('p5UIBtnAjax:Storage:addTableBaseProces:ajaxLoaded', function(e, n, payload) {
  348. jQuery.notify(payload.msg, payload.type);
  349. });
  350. ");
  351. if ('sort' === $sortByCol) {
  352. echo UI::h('script', [], "
  353. jQuery(document).ready(function (){
  354. var tblNode$ = jQuery('#struct_table > tbody')
  355. var getOrder = function () {
  356. var orderIds = []
  357. jQuery('#struct_table > tbody').children('.ta-sortable-item').each(function (idx, trNode) {
  358. orderIds.push(jQuery(trNode).data('id_zasob'))
  359. })
  360. return orderIds
  361. }
  362. var sortOrder = getOrder()
  363. console.log('sortOrder - init', sortOrder)
  364. tblNode$.sortable({
  365. axis: 'y',
  366. handle: '.ta-sortable-item-handle',
  367. items: '.ta-sortable-item',
  368. update: function (event, ui) {
  369. sortOrder = getOrder()
  370. tblNode$.sortable('disable')
  371. tblNode$.find('.ta-sortable-item-handle').css({color:'silver'})
  372. console.log('TODO: disable sortable while ajax')
  373. // window.setTimeout(function () {
  374. // tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  375. // console.log('TODO: ajax fetch result')
  376. // tblNode$.sortable('enable')
  377. // tblNode$.sortable('cancel')
  378. // }, 1000)
  379. window.fetch(
  380. URI(window.location.href)
  381. .setSearch('_task', 'updateAntAclSortAjax')
  382. .setSearch('idZasobOrder', sortOrder)
  383. .build().toString(),
  384. {
  385. method: 'POST',
  386. headers: {
  387. 'Content-Type': 'application/x-www-form-urlencoded' // query string
  388. },
  389. credentials: 'same-origin',
  390. body: JSON.stringify({
  391. namespace: URI.parseQuery(window.location.search).namespace,
  392. sortBy: '{$sortByCol}',
  393. sortByDir: '{$sortByDir}',
  394. sortOrder: sortOrder,
  395. })
  396. }
  397. ).then(function(response) {
  398. return response.json()
  399. }).then(function(payload) {
  400. console.log('updateAntAclSortAjax response', payload);
  401. tblNode$.sortable('enable')
  402. if ('success' !== payload.type) {
  403. tblNode$.sortable('cancel')
  404. }
  405. tblNode$.sortable('enable')
  406. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  407. p5UI__notifyAjaxCallback({
  408. type: payload.type || 'error',
  409. msg: payload.msg || 'Request error'
  410. });
  411. if ('success' === payload.type) {
  412. window.location.reload(true)
  413. }
  414. }).catch(function(e) {
  415. tblNode$.sortable('enable')
  416. tblNode$.sortable('cancel')
  417. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  418. p5UI__notifyAjaxCallback({
  419. type: 'error',
  420. msg: 'Request error ' + e
  421. });
  422. })
  423. }
  424. });
  425. });
  426. ");
  427. }
  428. }
  429. public function objectStructView($item) {
  430. $namespace = $item['namespace'];
  431. { // sortBy
  432. $sortByArgName = 'sortBy';
  433. $sortByCol = V::get($sortByArgName, 'namespace', $_GET);
  434. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $_GET);
  435. { // add SORT_PRIO
  436. $item['field'] = array_map(function ($field) {
  437. $field['SORT_PRIO'] = ($field['idZasob'] > 0)
  438. ? DB::getPDO()->fetchValue("
  439. select z.SORT_PRIO
  440. from CRM_LISTA_ZASOBOW z
  441. where z.ID = :id
  442. ", [ ':id' => $field['idZasob'] ])
  443. : null
  444. ;
  445. return $field;
  446. }, $item['field']);
  447. }
  448. if ('namespace' === $sortByCol) {
  449. usort($item['field'], function ($a, $b) use ($sortByDir) {
  450. if ($a['fieldNamespace'] > $b['fieldNamespace']) return 'asc' === $sortByDir ? 1 : -1;
  451. if ($a['fieldNamespace'] < $b['fieldNamespace']) return 'asc' === $sortByDir ? -1 : 1;
  452. return 0;
  453. });
  454. }
  455. else if ('sort' === $sortByCol) {
  456. usort($item['field'], function ($a, $b) use ($sortByDir) {
  457. if (null === $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return 0;
  458. if (null === $a['SORT_PRIO'] && null != $b['SORT_PRIO']) return 1;
  459. if (null !== $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return -1;
  460. if ($a['SORT_PRIO'] > $b['SORT_PRIO']) return 'asc' === $sortByDir ? 1 : -1;
  461. if ($a['SORT_PRIO'] < $b['SORT_PRIO']) return 'asc' === $sortByDir ? -1 : 1;
  462. return 0;
  463. });
  464. }
  465. echo UI::h('style', [ 'type' => "text/css" ], "
  466. .ta-ordering { cursor:pointer }
  467. .ta-ordering-desc:after { content:\"\\e252\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  468. .ta-ordering-asc:after { content:\"\\e253\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  469. .ta-sortable-item { }
  470. .ta-sortable-item-handle { cursor:pointer }
  471. ");
  472. echo UI::h('script', [ 'src' => "static/URI.js" ]);
  473. echo UI::h('script', [], "
  474. function p5UI_table_sortBy_get(n, argName, colName, dir) {
  475. var newUri = URI(window.location.href).setQuery(argName, colName).setQuery(argName+'Dir', dir).build().toString();
  476. window.location.href = newUri
  477. }
  478. ");
  479. }
  480. if ('setFieldRefConfig' === V::get('_postTask', '', $_POST)) {
  481. $field = V::get('field', '', $_POST);
  482. $source = V::get('source', '', $_POST);
  483. switch ($source) {
  484. case 'view':
  485. $refSelect = ACL::generateRefSelectSqlByFlatRelationCache($namespace, $field);
  486. ACL::setRefSource($namespace, $field, 'view', $refSelect);
  487. break;
  488. case 'table': ACL::setRefSource($namespace, $field, 'table'); break;
  489. }
  490. }
  491. if ('preview' === V::get('_postTask', '', $_POST)) {
  492. try {
  493. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  494. $localFields = array_filter($item['field'], function ($field) {
  495. return $field['isLocal'];
  496. });
  497. $refFields = array_filter($item['field'], function ($field) {
  498. return 'ref:' === substr($field['xsdType'], 0, 4);
  499. });
  500. $activeRefFields = array_filter($refFields, function ($field) {
  501. $refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  502. return (1 == DB::getPDO()->fetchValue("
  503. select t.isObjectActive
  504. from `CRM_#CACHE_ACL_OBJECT` t
  505. where t.`namespace` = '{$refNamespace}'
  506. "));
  507. });
  508. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery([])->getItems([
  509. 'limit' => 5
  510. ]);
  511. DBG::nicePrint($previewItems, 'items (default query) - preview (limit 5)');
  512. $query = [ 'cols' => array_merge(
  513. array_map(
  514. function ($field) {
  515. return $field['fieldNamespace'];
  516. }, $localFields
  517. ),
  518. array_map(
  519. function ($field) {
  520. return "{$field['fieldNamespace']}/*";
  521. }, $activeRefFields
  522. )
  523. ) ];
  524. DBG::nicePrint($query, 'items with ref/* - query');
  525. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  526. 'limit' => 5
  527. ]);
  528. DBG::nicePrint($previewItems, 'items with ref/* - preview (limit 5)');
  529. $query = [ 'cols' => array_merge(
  530. array_map(
  531. function ($field) {
  532. return $field['fieldNamespace'];
  533. }, $localFields
  534. ),
  535. array_map(
  536. function ($field) {
  537. return "{$field['fieldNamespace']}";
  538. }, $activeRefFields
  539. )
  540. ) ];
  541. DBG::nicePrint($query, 'items with ref as xlink - query');
  542. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  543. 'limit' => 5
  544. ]);
  545. DBG::nicePrint($previewItems, 'items with ref as xlink - preview (limit 5)');
  546. } catch (Exception $e) {
  547. DBG::log($e);
  548. UI::alert('danger', $e->getMessage());
  549. }
  550. }
  551. echo UI::h('details', ['style'=>"margin-bottom:24px; padding:0 10px; background-color:#eee", 'open' => "open"], [
  552. UI::h('summary', ['style'=>"font-size:1.4em; line-height:2em; cursor:pointer; outline:none"], [
  553. "Struktura obiektu '{$namespace}' ",
  554. // UI::h('small', ['style'=>"font-size:0.8em; font-style:italic; color:#aaa"], " więcej...")
  555. ]),
  556. UI::h('div', ['style'=>"padding:4px 24px; border-top:1px solid #fff"], [
  557. UI::h('span', ['style'=>"margin-right:12px"], [
  558. ( ($item['idZasob'] > 0)
  559. ? UI::h('span', [ 'title' => "Nr zasobu '{$item['idZasob']}'" ], "Nr zasobu [{$item['idZasob']}]")
  560. : UI::h('span', [ 'title' => "Brak nr zasobu - dodaj do zasobów" ], [
  561. UI::hButtonAjax("+ do zasobów", 'addAclObjectToZasobyAjax', [
  562. 'class' => "btn btn-xs btn-primary",
  563. 'href' => Router::getRoute('Storage')->getLink('addAclObjectToZasobyAjax'),
  564. 'data' => [
  565. 'idStorage' => $item['idDatabase'],
  566. 'namespace' => $item['namespace'],
  567. ]
  568. ])
  569. ])
  570. ),
  571. ]),
  572. UI::h('span', ['style'=>"margin:0 12px"], [
  573. ( ($item['isObjectActive'] > 0)
  574. ? UI::h('span', [ 'class' => "label label-success", 'title' => "Namespace active" ], "Active")
  575. : UI::h('span', [ 'title' => "Namespace not active" ], [
  576. ($item['idZasob'] > 0)
  577. ? UI::hButtonAjax("Aktywuj", 'activateObjectAjax', [
  578. 'class' => "btn btn-xs btn-primary",
  579. 'href' => Router::getRoute('Storage')->getLink('activateObjectAjax'),
  580. 'data' => [
  581. 'namespace' => $item['namespace'],
  582. ]
  583. ])
  584. : '',
  585. ])
  586. ),
  587. ]),
  588. UI::h('a', [
  589. 'href' => "index.php?_route=ViewTableAjax&namespace={$item['namespace']}",
  590. 'class' => "btn btn-sm btn-link"
  591. ], "Przeglądaj tabelę"),
  592. ( ($item['idZasob'] > 0)
  593. ? UI::h('a', [
  594. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$item['idZasob']}&filtr_ids=%2B&filtr_ob=%2B",
  595. 'class' => "btn btn-sm btn-link",
  596. 'title' => "Struktura tabeli w drzewie zasobów"
  597. ], "Zasoby")
  598. : ''
  599. ),
  600. ( ($item['idZasob'] > 0)
  601. ? UI::h('a', [
  602. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$item['idZasob']}",
  603. 'class' => "btn btn-sm btn-link",
  604. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  605. ], "Procesy")
  606. : ''
  607. ),
  608. UI::h('a', [
  609. 'href' => Router::getRoute('Storage')->getLink('objectReinstall', ['namespace' => $item['namespace']]),
  610. 'class' => 'btn btn-sm btn-link', 'style' => "color:#f00",
  611. 'title' => "Zainstaluje ponownie obiekt"
  612. ], "reinstall object"),
  613. UI::h('a', [
  614. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => $item['namespace'] ]),
  615. 'class' => "btn btn-sm btn-link",
  616. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  617. ], "Uprawnienia (analiza użycia)"),
  618. UI::hButtonPost("(podgląd z relacjami)", [
  619. 'data' => [
  620. '_postTask' => 'preview'
  621. ],
  622. 'class' => 'btn btn-sm btn-link', 'style' => "font-style:italic",
  623. 'title' => "Podgląd kilku ostatnich obiektów wraz z relacjami"
  624. ]),
  625. ])
  626. ]);
  627. $thisGetLink = [ $this, 'getLink' ];
  628. { // not installed ref
  629. $refFields = array_filter($item['field'], function ($field) {
  630. return ('ref:' === substr($field['xsdType'], 0, 4) && $field['isActive']);
  631. });
  632. UI::table([
  633. 'caption' => UI::h('span', [], "Obiekty powiązane (TODO backRef)"),
  634. 'rows' => array_map(function ($field) use ($thisGetLink) {
  635. $refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  636. $isInstalled = (1 == DB::getPDO()->fetchValue("
  637. select t.isObjectActive
  638. from `CRM_#CACHE_ACL_OBJECT` t
  639. where t.`namespace` = '{$refNamespace}'
  640. "));
  641. $refSource = null;
  642. if ($isInstalled) {
  643. try {
  644. $refTable = ACL::getRefTable($field['objectNamespace'], $field['fieldNamespace']);
  645. DBG::log($refTable, 'array', "getRefTable('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  646. $refSource = ACL::getRefSource($field['objectNamespace'], $field['fieldNamespace']);
  647. DBG::log($refSource, 'array', "ACL::getRefSource('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  648. } catch (Exception $e) {
  649. DBG::log($e);
  650. }
  651. }
  652. return [
  653. 'fieldName' => $field['fieldNamespace'],
  654. // 'xsdType' => $field['xsdType'], // always === "ref:{$field['fieldNamespace']}"
  655. 'ref object' => UI::h('a', [
  656. 'class' => "btn btn-xs btn-link",
  657. 'href' => $thisGetLink('', [ 'namespace' => $refNamespace ])
  658. ], "objectStruct ({$refNamespace})"),
  659. 'ref source' => UI::h('div', [],
  660. (null === $refSource)
  661. ? [ "ref object not installed" ] // TODO: link to install? is table struct
  662. : [
  663. // UI::hButtonAjax("Tabela ref", "setFieldRefConfig", [
  664. // 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  665. // 'href' => $thisGetLink('setFieldRefConfig'),
  666. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'table' ]
  667. // ]),
  668. // UI::hButtonAjax("Widok (cache)", "setFieldRefConfig", [
  669. // 'title' => "Według flat_relation_cache",
  670. // 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  671. // 'href' => $thisGetLink('setFieldRefConfig'),
  672. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'view' ]
  673. // ]),
  674. UI::hButtonPost("Tabela ref", [
  675. 'title' => "Według wygenerowanej tabeli REF",
  676. 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  677. // 'href' => $thisGetLink('setFieldRefConfig'),
  678. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'table' ]
  679. ]),
  680. UI::hButtonPost("Widok (cache)", [
  681. 'title' => "Według flat_relation_cache",
  682. 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  683. // 'href' => $thisGetLink('setFieldRefConfig'),
  684. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'view' ]
  685. ]),
  686. ]
  687. ),
  688. '@class' => ($isInstalled) ? "success" : "danger",
  689. ]; // TODO: link to install object
  690. }, $refFields)
  691. ]);
  692. }
  693. $thisGetLink = [ $this, 'getLink' ];
  694. UI::table([
  695. '__html_id' => 'struct_table',
  696. 'caption' => UI::h('span', [], [
  697. UI::h('span', [ 'style' => "margin-right:6px;color:#000" ], "Struktura obiektu '{$item['namespace']}'"),
  698. ]),
  699. // 'sortBy' => [
  700. // 'method' => 'get',
  701. // 'argName' => '_sortBy',
  702. // 'allow' => ['sort', 'namespace'],
  703. // 'default' => ['namespace', 'asc'],
  704. // ],
  705. 'cols_label' => [
  706. 'sort' => UI::h('nobr', [
  707. 'class' => "ta-ordering" . ('sort' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  708. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'sort', '" . ('sort' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  709. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  710. ], "sort"),
  711. 'namespace' => UI::h('nobr', [
  712. 'class' => "ta-ordering" . ('namespace' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  713. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'namespace', '" . ('namespace' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  714. 'title' => "Sortuj wg nazwy pola",
  715. ], "namespace"),
  716. ],
  717. 'rows' => array_map(function ($field) use ($item, $thisGetLink, $sortByCol) {
  718. $tblItem = [];
  719. if ('sort' === $sortByCol && null !== $field['SORT_PRIO'] && !empty($field['idZasob'])) {
  720. $tblItem['@class'] = "ta-sortable-item";
  721. $tblItem['@class[sort]'] = "ta-sortable-item-handle";
  722. $tblItem['@data']['sort_prio'] = $field['SORT_PRIO'];
  723. $tblItem['@data']['id_zasob'] = $field['idZasob'];
  724. $field['SORT_PRIO'] = ":: {$field['SORT_PRIO']}";
  725. }
  726. $tblItem['sort'] = V::get('SORT_PRIO', null, $field);
  727. foreach ($field as $k => $v) {
  728. if ('SORT_PRIO' === $k) continue;
  729. $tblItem[$k] = $v;
  730. }
  731. $tblItem['namespace'] = UI::h('span', [], [
  732. UI::h('span', ['style' => "color:#aaa"], substr($field['namespace'], 0, strlen($field['objectNamespace']) + 1)),
  733. UI::h('span', ['style' => "color:#000"], substr($field['namespace'], strlen($field['objectNamespace']) + 1)),
  734. ]);
  735. $tblItem['idZasob'] = ($field['idZasob'] > 0)
  736. ? $field['idZasob']
  737. : (
  738. ($item['idZasob'] > 0)
  739. ? UI::hButtonAjax("+ do zasobów", 'addFieldToZasobyAjax', [
  740. 'class' => "btn btn-xs btn-primary",
  741. 'href' => $thisGetLink('addFieldToZasobyAjax'),
  742. 'data' => [
  743. 'namespace' => $item['namespace'],
  744. 'fieldNamespace' => $field['namespace'],
  745. ]
  746. ])
  747. : UI::h('span', ['title'=>"Brak Nr zasobu dla obiektu", 'class'=>"btn btn-xs btn-danger"], "Brak nr zasobu obiektu")
  748. )
  749. ;
  750. unset($tblItem['objectNamespace']);
  751. unset($tblItem['fieldNamespace']);
  752. return $tblItem;
  753. }, array_filter($item['field'], function ($field) { return $field['isActive']; }))
  754. ]);
  755. $removedFields = array_filter($item['field'], function ($field) { return !$field['isActive']; });
  756. if (!empty($removedFields)) {
  757. // echo UI::h('details', [ 'style' => "padding:6px; background-color:#333; color:#fff", 'open' => "open" ], [
  758. // UI::h('summary', [ 'style' => "padding:0 3px; outline:none; cursor:pointer" ], "WFS Response converted to JSON"),
  759. // UI::h('pre', [ 'id' => 'wfsResponse', 'style' => "margin:0; font-size:x-small; border-radius:0" ], 'loading...'),
  760. echo UI::h('details', [ 'style' => "margin-bottom:12px; padding:6px; background-color:#dedede; color:#000" ], [
  761. UI::h('summary', [ 'style' => "padding:0 3px; outline:none; cursor:pointer" ], "Pola w koszu (".count($removedFields).")"),
  762. UI::h('table', [ 'style' => "margin:6px 0 0 0; background-color:#fff; font-size:x-small", 'class' => "table table-bordered table-hover table-condensed" ], [
  763. UI::h('thead', [], [
  764. UI::h('tr', [], [
  765. UI::h('th', [], "#"),
  766. UI::h('th', [], "namespace"),
  767. UI::h('th', [], "xsdType"),
  768. UI::h('th', [], "xsdRestrictions"),
  769. UI::h('th', [], "appInfo"),
  770. UI::h('th', [], "minOccurs"),
  771. UI::h('th', [], "maxOccurs"),
  772. UI::h('th', [], "isActive"),
  773. ]),
  774. ]),
  775. UI::h('tbody', [], array_map(function ($field) use ($item, $thisGetLink) {
  776. return UI::h('tr', [], [
  777. UI::h('td', [], [
  778. UI::hButtonAjax("usuń", 'removeFieldFromTrashAjax', [
  779. 'class' => "btn btn-xs btn-danger",
  780. 'href' => $thisGetLink('removeFieldFromTrashAjax'),
  781. 'data' => [
  782. 'namespace' => $item['namespace'],
  783. 'fieldNamespace' => $field['namespace'],
  784. ]
  785. ])
  786. ]),
  787. UI::h('td', [], $field['fieldNamespace']),
  788. UI::h('td', [], $field['xsdType']),
  789. UI::h('td', [], $field['xsdRestrictions']),
  790. UI::h('td', [], $field['appInfo']),
  791. UI::h('td', [], $field['minOccurs']),
  792. UI::h('td', [], $field['maxOccurs']),
  793. UI::h('td', [], $field['isActive']),
  794. ]);
  795. }, $removedFields)),
  796. ]),
  797. ]);
  798. }
  799. UI::hButtonAjaxOnResponse('removeFieldFromTrashAjax', /* payload, n */ "
  800. if (!payload.type) return false
  801. jQuery.notify(payload.msg, payload.type)
  802. if ('success' == payload.type) {
  803. var trJqNode = jQuery(n).closest('tr')
  804. var tbodyJqNode = trJqNode.parent()
  805. var detailsJqNode = trJqNode.closest('details')
  806. trJqNode.remove()
  807. if (!tbodyJqNode.children().length) {
  808. detailsJqNode.remove()
  809. }
  810. }
  811. ");
  812. UI::hButtonAjaxOnResponse('addFieldToZasobyAjax', /* payload, n */ "
  813. if (!payload.type) return false
  814. if (payload.body && payload.body.id && payload.body.id > 0) { // if ('success' == payload.type) {
  815. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  816. }
  817. jQuery.notify(payload.msg, payload.type)
  818. ");
  819. UI::hButtonAjaxOnResponse('addAclObjectToZasobyAjax', /* payload, n */ "
  820. if (!payload.type) return false
  821. if ('success' === payload.type || 'info' === payload.type) {
  822. if (payload.body && payload.body.id && payload.body.id > 0) {
  823. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  824. } else {
  825. console.log('TODO: addAclObjectToZasobyAjax unknown response', payload);
  826. }
  827. window.location.reload()
  828. }
  829. ");
  830. UI::hButtonAjaxOnResponse('activateObjectAjax', /* payload, n */ "
  831. jQuery.notify(payload.msg, payload.type)
  832. if (!payload.type) return false
  833. if ('success' === payload.type || 'info' === payload.type) {
  834. if (payload.body && payload.body.isObjectActive && payload.body.isObjectActive > 0) {
  835. n.parentNode.replaceChild(document.createTextNode('Active'), n)
  836. } else {
  837. console.log('TODO: activateObjectAjax unknown response', payload);
  838. }
  839. }
  840. ");
  841. if ('sort' === $sortByCol) {
  842. echo UI::h('script', [], "
  843. jQuery(document).ready(function (){
  844. var tblNode$ = jQuery('#struct_table > tbody')
  845. var getOrder = function () {
  846. var orderIds = []
  847. jQuery('#struct_table > tbody').children('.ta-sortable-item').each(function (idx, trNode) {
  848. orderIds.push(jQuery(trNode).data('id_zasob'))
  849. })
  850. return orderIds
  851. }
  852. var sortOrder = getOrder()
  853. console.log('sortOrder - init', sortOrder)
  854. tblNode$.sortable({
  855. axis: 'y',
  856. handle: '.ta-sortable-item-handle',
  857. items: '.ta-sortable-item',
  858. update: function (event, ui) {
  859. sortOrder = getOrder()
  860. tblNode$.sortable('disable')
  861. tblNode$.find('.ta-sortable-item-handle').css({color:'silver'})
  862. console.log('TODO: disable sortable while ajax')
  863. // window.setTimeout(function () {
  864. // tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  865. // console.log('TODO: ajax fetch result')
  866. // tblNode$.sortable('enable')
  867. // tblNode$.sortable('cancel')
  868. // }, 1000)
  869. window.fetch(
  870. URI(window.location.href)
  871. .setSearch('_task', 'updateAntAclSortAjax')
  872. .setSearch('idZasobOrder', sortOrder)
  873. .build().toString(),
  874. {
  875. method: 'POST',
  876. headers: {
  877. 'Content-Type': 'application/x-www-form-urlencoded' // query string
  878. },
  879. credentials: 'same-origin',
  880. body: JSON.stringify({
  881. namespace: URI.parseQuery(window.location.search).namespace,
  882. sortBy: '{$sortByCol}',
  883. sortByDir: '{$sortByDir}',
  884. sortOrder: sortOrder,
  885. })
  886. }
  887. ).then(function(response) {
  888. return response.json()
  889. }).then(function(payload) {
  890. console.log('updateAntAclSortAjax response', payload);
  891. tblNode$.sortable('enable')
  892. if ('success' !== payload.type) {
  893. tblNode$.sortable('cancel')
  894. }
  895. tblNode$.sortable('enable')
  896. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  897. p5UI__notifyAjaxCallback({
  898. type: payload.type || 'error',
  899. msg: payload.msg || 'Request error'
  900. });
  901. if ('success' === payload.type) {
  902. window.location.reload(true)
  903. }
  904. }).catch(function(e) {
  905. tblNode$.sortable('enable')
  906. tblNode$.sortable('cancel')
  907. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  908. p5UI__notifyAjaxCallback({
  909. type: 'error',
  910. msg: 'Request error ' + e
  911. });
  912. })
  913. }
  914. });
  915. });
  916. ");
  917. }
  918. if ($item['isObjectActive']) {
  919. echo UI::hButtonAjax("Dodaj podstawowy proces dla obiektu '{$item['namespace']}' - read only (TODO)", 'addObjectBaseProcesAjax', [
  920. 'class' => "btn btn-xs btn-default",
  921. 'href' => Router::getRoute('Storage')->getLink('addObjectBaseProcesAjax'),
  922. 'data' => [ 'namespace' => $item['namespace'] ]
  923. ]);
  924. UI::hButtonAjaxOnResponse('addObjectBaseProcesAjax', /* payload, n */ "
  925. jQuery.notify(payload.msg, payload.type)
  926. ");
  927. }
  928. DBG::nicePrint($item, '$item');
  929. }
  930. public function updateAntAclSortAjaxAction() {
  931. return Response::sendTryCatchJson(array($this, 'updateAntAclSortAjax'), $args = 'JSON_FROM_REQUEST_BODY');
  932. }
  933. public function updateAntAclSortAjax($args) {
  934. DBG::log($args, 'array', "args");
  935. $namespace = V::get('namespace', '', $args);
  936. if (empty($namespace)) throw new Exception("Missing param namespace");
  937. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  938. DBG::log($item, 'array', "\$item");
  939. $sortByArgName = 'sortBy';
  940. $sortByCol = V::get($sortByArgName, 'namespace', $args);
  941. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $args);
  942. if ('sort' !== $sortByCol) throw new Exception("Only sort by SORT_PRIO allowed to update");
  943. if (!in_array($sortByDir, ['asc', 'desc'])) throw new Exception("Wrong order by dir arg");
  944. if ('asc' !== $sortByDir) throw new Exception("Only sort asc is allowed"); // DBG
  945. $sortPrioIdsFromZasoby = DB::getPDO()->fetchAll("
  946. select z.ID, z.SORT_PRIO
  947. from CRM_LISTA_ZASOBOW z
  948. where z.PARENT_ID = :p_id
  949. order by z.SORT_PRIO asc, z.ID asc -- default order in Zasoby tree
  950. ", [
  951. ':p_id' => $item['idZasob']
  952. ]);
  953. DBG::log($sortPrioIdsFromZasoby, 'array', "\$sortPrioIdsFromZasoby");
  954. $idZasobCurrentOrder = array_map(function ($orderRow) {
  955. return (int)$orderRow['ID'];
  956. }, $sortPrioIdsFromZasoby);
  957. DBG::log($idZasobCurrentOrder, 'array', "\$idZasobCurrentOrder");
  958. DBG::log(array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder), 'array', "array_diff_assoc(\$args['sortOrder'], \$idZasobCurrentOrder)");
  959. DBG::log(array_diff_assoc($idZasobCurrentOrder, $args['sortOrder']), 'array', "array_diff_assoc(\$idZasobCurrentOrder, \$args['sortOrder'])");
  960. $orderDiff = array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder);
  961. foreach ($orderDiff as $sortPrio => $idZasob) {
  962. DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $idZasob, [
  963. 'SORT_PRIO' => $sortPrio,
  964. ]);
  965. }
  966. return [
  967. 'type' => 'success',
  968. 'msg' => "OK",
  969. 'DBG__args' => $args
  970. ];
  971. }
  972. public function removeFieldFromTrashAjaxAction() {
  973. DBG::log($_REQUEST, 'array', '$_REQUEST');
  974. Response::sendTryCatchJson(array($this, 'removeFieldFromTrashAjax'), $_REQUEST);
  975. }
  976. public function removeFieldFromTrashAjax($args) {
  977. $namespace = V::get('namespace', '', $args);
  978. if (empty($namespace)) throw new HttpException("Missing namespace");
  979. $fieldNamespace = V::get('fieldNamespace', '', $args);
  980. if (empty($fieldNamespace)) throw new HttpException("Missing fieldNamespace");
  981. $fieldItem = SchemaFactory::loadDefaultObject('SystemObjectField')->getItem($fieldNamespace);
  982. if (!$fieldItem) throw new HttpException("Field not found '{$fieldNamespace}'", 404);
  983. DBG::log($fieldItem, 'array', "\$fieldItem");
  984. switch ($fieldItem['xsdType']) {
  985. case 'p5:enum': throw new Exception("TODO: remove enum values first"); break; // CRM_#CACHE_ACL_OBJECT_FIELD_enum
  986. default: {
  987. if ('ref:' === substr($fieldItem['xsdType'], 0, 4)) { // OK, remove
  988. } else throw new Exception("TODO: remove xsdType: {$fieldItem['xsdType']}");
  989. }
  990. }
  991. DB::getPDO()->execSql("
  992. DELETE from `CRM_#CACHE_ACL_OBJECT_FIELD`
  993. where namespace = :namespace
  994. and objectNamespace = :objectNamespace
  995. and _rootTableName = :rootTableName
  996. and isActive = 0
  997. limit 1
  998. ", [
  999. 'namespace' => $fieldItem['namespace'],
  1000. 'objectNamespace' => $fieldItem['objectNamespace'],
  1001. 'rootTableName' => $fieldItem['_rootTableName'],
  1002. ]);
  1003. return [
  1004. 'type' => "success",
  1005. 'msg' => "Usunięto pole {$fieldItem['fieldNamespace']}",
  1006. ];
  1007. }
  1008. public function addFieldToZasobyAjaxAction() {
  1009. DBG::log($_REQUEST, 'array', '$_REQUEST');
  1010. Response::sendTryCatchJson(array($this, 'addFieldToZasobyAjax'), $_REQUEST);
  1011. }
  1012. public function addFieldToZasobyAjax($args) {
  1013. $namespace = V::get('namespace', '', $args);
  1014. if (empty($namespace)) throw new HttpException("Missing namespace");
  1015. $fieldNamespace = V::get('fieldNamespace', '', $args);
  1016. if (empty($fieldNamespace)) throw new HttpException("Missing fieldNamespace");
  1017. $fieldItem = SchemaFactory::loadDefaultObject('SystemObjectField')->getItem($fieldNamespace);
  1018. if (!$fieldItem) throw new HttpException("Field not found '{$fieldNamespace}'", 404);
  1019. DBG::log($fieldItem, 'array', "\$fieldItem");
  1020. if ($fieldItem['idZasob'] > 0) throw (new AlertSuccessException("Field already added to Zasoby '{$fieldItem['idZasob']}'"))->setBody([ 'id' => $fieldItem['idZasob'] ]);
  1021. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace);
  1022. if (!$objectItem) throw new HttpException("Object not found '{$namespace}'", 404);
  1023. DBG::log($objectItem, 'array', "\$objectItem");
  1024. if (!$objectItem['idZasob']) throw new Exception("Missing Object idZasob");
  1025. $zasobItem = DB::getPDO()->fetchFirst("
  1026. select zField.ID, zField.`DESC`, zField.`TYPE`, zField.PARENT_ID
  1027. from CRM_LISTA_ZASOBOW as zField
  1028. join CRM_LISTA_ZASOBOW as zTable on(zTable.ID = zField.PARENT_ID)
  1029. where zTable.`ID` = '{$objectItem['idZasob']}'
  1030. and zTable.`TYPE` = 'TABELA'
  1031. and zField.`DESC` = '{$fieldItem['fieldNamespace']}'
  1032. and zField.`TYPE` = 'KOMORKA'
  1033. ");
  1034. if ($zasobItem) {
  1035. SchemaFactory::loadDefaultObject('SystemObjectField')->updateItem([
  1036. 'namespace' => $fieldItem['namespace'],
  1037. 'idZasob' => $zasobItem['ID']
  1038. ]);
  1039. throw (new AlertSuccessException("Zasob już istnieje"))->setBody([ 'id' => $zasobItem['ID'] ]);
  1040. }
  1041. $newFieldItem = [
  1042. 'PARENT_ID' => $objectItem['idZasob'],
  1043. 'TYPE' => 'KOMORKA',
  1044. 'DESC' => $fieldItem['fieldNamespace'],
  1045. 'DESC_PL' => $fieldItem['fieldNamespace'],
  1046. ];
  1047. DBG::log($newFieldItem, 'array', "add new field item");
  1048. try {
  1049. $acl = User::getAcl()->getObjectAcl('default_db', 'crm_lista_zasobow');
  1050. } catch (Exception $e) {
  1051. throw new Exception("Brak dostępu do tabeli Zasoby");
  1052. }
  1053. $createdId = $acl->addItem($newFieldItem);
  1054. if (!$createdId) throw new Exception("Nie udało się utworzyć nowego rekordu!");
  1055. SchemaFactory::loadDefaultObject('SystemObjectField')->updateItem([
  1056. 'namespace' => $fieldItem['namespace'],
  1057. 'idZasob' => $createdId
  1058. ]);
  1059. throw (new AlertSuccessException("Utworzono pomyślnie rekord nr {$createdId}"))->setBody([ 'id' => $createdId ]);
  1060. }
  1061. }