"pull-right" ], [ UI::h('a', [ 'href' => $this->getLink('listLastJobs'), 'class' => "btn btn-link", ], "Ostatnio uruchione"), UI::hButtonPost("Odśwież", [ 'class' => "btn btn-link", // 'form.class' => "pull-right", 'title' => "Wczytaj ponownie listę dostępnych funkcji", 'data' => [ 'forceUpdate' => '1', ] ]), ]); echo UI::h('h1', [], 'Druki'); UI::tryCatchView([ $this, 'listAntView' ]); UI::endContainer(); UI::dol(); } function listAntView() { $taskList = $this->getAntUrlActionList(); // $featureID = V::get('featureID', '', $_GET); $primaryKey = V::get('primaryKey', '', $_GET, 'word'); $typeName = V::get('typeName', '', $_GET, 'word'); if (empty($typeName)) throw new Exception("Missing typeName"); if (empty($primaryKey)) throw new Exception("Missing primaryKey"); $parsedInfo = Core_AclHelper::parseTypeName($typeName); DBG::log($parsedInfo, '', "Ant parseTypeName({$typeName})"); $acl = ACL::getAclByNamespace("{$parsedInfo['url']}/{$parsedInfo['name']}"); $pkField = $acl->getPrimaryKeyField(); echo UI::h('p', [ 'class' => "text-muted" ], [ "Druki dla rekordu '{$primaryKey}' w tabeli ", UI::h('a', [ 'href' => Router::getRoute('ViewTableAjax')->getLink('', [ 'namespace' => $acl->getNamespace() ]) ], $acl->getRawLabel()), ]); UI::inlineJS( __FILE__ . '.async.js', [ // p5UI_runAntAsyncJob 'RUN_ANT_JOB_URL' => $this->getLink('startAntJobAjax'), 'RUN_TEST_ANT_JOB_URL' => $this->getLink('startTestAntJobAjax'), ]); // echo UI::h('div', [ 'style' => "padding-bottom:8px; border-bottom:1px solid #eee;" ], [ // UI::h('select', [ 'class' => "form-control" ], array_map(function ($label, $path) { // return UI::h('option', [ 'value' => $path ], $label); // }, $taskList, array_keys($taskList))), // ]); UI::startTag('ul'); foreach ($taskList as $path => $label) { echo UI::h('li', [], [ UI::h('a', [ 'class' => 'btn btn-md btn-link', 'href' => $this->getLink('ant', [ 'path' => $path, 'typeName' => $typeName, 'primaryKey' => $primaryKey, 'primaryKeyField' => $pkField ]) ], "Uruchom '{$label}'") ]); $tmpls = $this->getAntUrlActionTemplates($path); if (!empty($tmpls)) { foreach ($tmpls as $tmpl => $labelTmpl) { echo UI::h('div', [ 'style' => "padding-left: 50px" ], [ UI::h('a', [ 'href' => $this->getLink('ant', [ 'path' => $path, 'template' => $tmpl, 'typeName' => $typeName, 'primaryKey' => $primaryKey, 'primaryKeyField' => $pkField ]), 'class' => 'btn btn-sm btn-link', ], ' ' . $labelTmpl), " ", UI::h('a', [ 'href' => $this->getLink('ant', [ 'path' => $path, 'template' => $tmpl, 'typeName' => $typeName, 'primaryKey' => $primaryKey, 'primaryKeyField' => $pkField ]), 'onclick' => 'return p5UI_runAntAsyncJob(event, this)', 'data-namespace' => $acl->getNamespace(), 'data-primaryKey' => $primaryKey, 'data-ant_path' => $path, 'data-ant_template' => $tmpl, 'class' => 'btn btn-xs btn-default', 'title' => "Uruchom asynchronicznie", ], "uruchom"), " ", // UI::h('a', [ // 'href' => $this->getLink('ant', [ // 'path' => $path, // 'template' => $tmpl, // 'typeName' => $typeName, // 'primaryKey' => $primaryKey, // 'primaryKeyField' => $pkField // ]), // 'onclick' => 'return p5UI_runAntAsyncJob(event, this, { TEST: 1 })', // 'data-namespace' => $acl->getNamespace(), // 'data-primaryKey' => $primaryKey, // 'data-ant_path' => $path, // 'data-ant_template' => $tmpl, // 'class' => 'btn btn-xs btn-link', // 'title' => "TEST Uruchom asynchronicznie", // ], "test"), ]); } } } UI::endTag('ul'); } function listLastJobsAction() { UI::layout([ get_called_class(), 'listLastJobsView' ]); } static function listLastJobsView() { echo UI::h('ol', [ 'class' => "breadcrumb" ], [ UI::h('li', [], [ UI::h('a', [ 'href' => self::link() ], [ UI::h('i', [ 'class' => "glyphicon glyphicon-home", 'style' => "margin-right:6px" ]), // TODO: mv to h('p5:icon', [ 'type' => "home" ]) " ", "Druki", ]), ]), UI::h('li', [], [ "Ostatnio uruchomione zadania", ]), ]); echo UI::h('h1', [], "Ostatnio uruchomione zadania"); $postTask = V::get('postTask', '', $_POST); if ('asyncJobStart' === $postTask) UI::tryCatchView([ get_called_class(), 'asyncJobStartPostTask' ], [ 'args' => $_POST ]); UI::table([ 'disable_lp' => true, 'rows' => array_map(function ($item) { return array_merge( [ '#' => '', 'Nr' => '', 'Status' => '', ], $item, [ '#' => self::jobListItem_Akcje($item), 'Nr' => $item['ID'], 'Status' => self::jobListItem_Status($item['A_STATUS'], $item), ] ); }, self::fetchUserLastAsyncJobs()), ]); throw new Exception("TODO: list last jobs"); } static function fetchUserLastAsyncJobs() { return DB::getPDO()->fetchAll(" select j.* from CRM_ASYNC_JOB_LOG j where j.USER = :user order by ID DESC ", [ ':user' => User::getLogin(), ]); } static function jobListItem_Akcje($item) { return UI::h('div', [ 'class' => "btn-group" ], [ UI::h('button', [ // 'type' => "button", 'class' => "btn btn-xs btn-default dropdown-toggle", 'data-toggle' => "dropdown", ], [ // UI::h('i', [ 'class' => "glyphicon glyphicon-hamburder" ]) 'Akcje ', UI::h('span', [ 'class' => "caret" ]), ]), UI::h('ul', [ 'class' => "dropdown-menu" ], [ UI::h('li', [], [ UI::h('a', [ 'href' => self::link('asyncJobDebug', [ 'id' => $item['ID'] ]), ], "Debug Info '{$item['ID']}'"), ]), UI::h('li', [], [ UI::hButtonPost("Uruchom zadanie '{$item['ID']}'", [ 'class' => "p5-hover", 'style' => "padding:3px 20px", // 'form.class' => "pull-right", // 'title' => "", 'data' => [ 'postTask' => 'asyncJobStart', 'id' => $item['ID'], ] ]), ]), // ]), ]); } static function jobListItem_Status($status, $item) { switch ($status) { case 'WAITING': return UI::h(null, null, [ "Oczekujący", ]); case 'NORMAL': return UI::h(null, null, [ "Uruchomiony", ]); case 'OFF_HARD': return UI::h(null, null, [ "Zakończony", ]); default: return UI::h(null, null, $status); } } static function asyncJobStartPostTask($args) { DBG::nicePrint($args, 'DBG: $args'); $idJob = V::get('id', 0, $args, 'int'); if ($idJob <= 0) throw new Exception("Missing id"); Lib::loadClass('Core_AsyncJobs'); Core_AsyncJobs::startAsyncJob($idJob); throw new Exception("TODO: asyncJobStartPostTask"); } function asyncJobDebugAction() { UI::layout([ $this, 'asyncJobDebugView' ]); } function asyncJobDebugView() { echo UI::h('ul', [ 'class' => "breadcrumb" ], [ UI::h('li', [], [ UI::h('a', [ 'href' => $this->getLink('listLastJobs') ], "Ostatnio uruchomione zadania"), ]), UI::h('li', [ 'class' => "active" ], [ "Zadanie - Debug", ]), ]); $idJob = V::get('id', 0, $_GET, 'int'); if ($idJob <= 0) throw new Exception("Missing job ID"); $item = DB::getPDO()->fetchFirst(" select j.ID -- , j.ID_FUNCTION -- , j.ID_SOURCE_JOB -- , j.P_ID , j.DATE -- 2020-02-26 -- , j.VERSION , j.JOB_NAME -- Ant|default_db/IN7_DZIENNIK_KORESP|default_db.in7_dziennik_koresp/test-async|test-loop , j.LOCK_VALUE -- 66263 -- , j.USER , j.A_STATUS , j.A_RECORD_CREATE_DATE , j.A_RECORD_CREATE_AUTHOR , j.A_RECORD_UPDATE_DATE , j.A_RECORD_UPDATE_AUTHOR from CRM_ASYNC_JOB_LOG j where j.USER = :user and j.ID = :id ", [ ':id' => $idJob, ':user' => User::getLogin(), ]); if (!$item) throw new Exception("Zadanie nie istnieje"); DBG::nicePrint($item, "Zadanie '{$idJob}'"); // TODO: files list in task folder Lib::loadClass('Core_AsyncJobsFiles'); $basePath = Core_AsyncJobsFiles::basePath($item['ID'], $item['DATE']); $propertyFile = Core_AsyncJobsFiles::propertyFile($item['ID'], $item['DATE']); $startScript = Core_AsyncJobsFiles::startScript($item['ID'], $item['DATE']); $outLog = Core_AsyncJobsFiles::outLog($item['ID'], $item['DATE']); $errorLog = Core_AsyncJobsFiles::errorLog($item['ID'], $item['DATE']); DBG::nicePrint([ 'basePath' => $basePath, 'propertyFile' => $propertyFile, 'startScript' => $startScript, 'outLog' => $outLog, 'errorLog' => $errorLog, ], "DBG:job files"); DBG::nicePrint(shell_exec("ls -l '{$basePath}'"), 'DBG: basePath'); DBG::nicePrint(shell_exec("cat '{$propertyFile}'"), 'DBG: propertyFile'); DBG::nicePrint(shell_exec("cat '{$startScript}'"), 'DBG: startScript'); DBG::nicePrint(shell_exec("cat '{$outLog}'"), 'DBG: outLog'); DBG::nicePrint(shell_exec("cat '{$errorLog}'"), 'DBG: errorLog'); throw new Exception("TODO: asyncJobDebug"); } public function outputAction() {// index.php?_route=UrlAction_Ant&_task=output & path={$path} & file={$file}"; $path = V::get('path', '', $_GET); if (!$path) throw new Exception("Missing Ant path!"); $file = V::get('file', '', $_GET); if (!$file) throw new Exception("Missing Ant file!"); // TODO: allow auth by token? throw new Exception("TODO: return output file '$file' from ant task '{$path}'"); } function startTestAntJobAjaxAction() { Response::sendTryCatchJson([ $this, 'startTestAntJobAjax' ], $args = 'JSON_FROM_REQUEST_BODY'); } function startTestAntJobAjax($args) { sleep(2); $ret = rand(0, 1); switch ($ret) { case 1: return [ 'type' => "success", 'msg' => "Dodano zadanie", 'body' => [ 'id_job' => 123, ], ]; // default: throw new Exception("TODO:startAntJobAjax"); default: return [ 'type' => "error", 'msg' => "Wystąpił błąd podczas dodawania zadania", ]; } } function startAntJobAjaxAction() { Response::sendTryCatchJson([ $this, 'startAntJobAjax' ], $args = 'JSON_FROM_REQUEST_BODY'); } function startAntJobAjax($args) { // $args = body: JSON.stringify({ // namespace: "default_db/IN7_DZIENNIK_KORESP" // primaryKey: "66263" // ant_path: "default_db.in7_dziennik_koresp/test-bash" // ant_template: "test-loop" // }) $namespace = V::get('namespace', '', $args); $primaryKey = V::get('primaryKey', '', $args); $ant_path = V::get('ant_path', '', $args); $ant_template = V::get('ant_template', '', $args); if (empty($namespace)) throw new Exception("Missing namespace"); if (empty($primaryKey)) throw new Exception("Missing primaryKey"); if (empty($ant_path)) throw new Exception("Missing ant_path"); if (empty($ant_template)) throw new Exception("Missing ant_template"); // TODO: convert antAction to async mode // - register async job or get jobID // - if exists: show last call info (result, when, etc.) + run again btn // - if not exists: create new folder with base files, create exec script, run this script in pm2 start // - parse result into AsyncJob/output and AsyncJob/output_type Lib::loadClass('Core_AsyncJobs'); $idJob = Core_AsyncJobs::registerNewAntTask([ 'namespace' => $namespace, 'primaryKey' => $primaryKey, 'ant_path' => $ant_path, 'ant_template' => $ant_template, ]); if (!$idJob) throw new Exception("Wystąpił błąd podczas dodawania zadania"); return [ 'type' => "success", 'msg' => "Dodano zadanie", '__DBG__args' => $args, ]; } public function antAction() { UI::gora(); UI::startContainer(); try { $path = V::get('path', '', $_GET); if (!$path) throw new Exception("Missing Ant path!"); $typeName = V::get('typeName', '', $_GET); if (!$typeName) throw new Exception("Missing typeName"); $primaryKey = V::get('primaryKey', '', $_GET); if (!$primaryKey) throw new Exception("Missing primaryKey"); $pkField = V::get('primaryKeyField', '', $_GET); if (!$pkField) throw new Exception("Missing primaryKeyField"); // list($nsPrefix, $objectName) = explode(':', $typeName);// TODO: get wfs prefix from typeName $parsedInfo = Core_AclHelper::parseTypeName($typeName); DBG::log($parsedInfo, '', "Ant parseTypeName({$typeName})"); $nsPrefix = $parsedInfo['prefix']; $objectName = $parsedInfo['name']; $template = V::get('template', '', $_GET); $confirmAntfile = V::get('confirmAntfile', '', $_GET); $confirmAntfileTarget = V::get('confirmAntfileTarget', '', $_GET); // TODO: validate missing ... DBG::log($_GET, 'array', '$_GET'); DBG::log([ 'msg'=>'$path', '$path'=>$path]); DBG::log([ 'msg'=>'$primaryKey', '$primaryKey'=>$primaryKey]); DBG::log([ 'msg'=>'$typeName', '$typeName'=>$typeName]); $taskList = $this->getAntUrlActionList(); if (!array_key_exists($path, $taskList)) throw new Exception("Ant path not exists! '{$path}'"); echo UI::h('h3', [], [ "Druk", '
', UI::h('small', [], $taskList[$path]) ]); echo UI::h('hr'); $webRootUrl = Request::getPathUri() . "schema/ant-url_action/{$path}";// TODO: security - only for test $outputFunctionUrl = $this->getLink('output') . "&path={$path}&file="; $antFunctionUrl = $this->getLink('ant') . "&path={$path}&file={$file}&template={$template}&typeName={$typeName}&primaryKey={$primaryKey}&primaryKeyField={$pkField}"; // &confirmAntfile={$confirmAntfile}&confirmAntfileTarget={$confirmAntfileTarget} sdo confirmacji potrzebne - wzglednie przetwarzac z tresci output URL_TASK - ale potrzebne parametry analogiczne aby chodzily DBG::log([ 'msg'=>'$webRootUrl', '$webRootUrl'=>$webRootUrl]); DBG::log([ 'msg'=>'$outputFunctionUrl', '$outputFunctionUrl'=>$outputFunctionUrl]); $testUrl = Request::getPathUri() . "wfs-data.php/default_db/?SERVICE=WFS&VERSION=1.0.0&TYPENAME={$typeName}&SRSNAME=EPSG:3003&featureID={$objectName}.{$primaryKey}";// &REQUEST=GetFeature // $testUrl = Request::getPathUri() . "wfs-data.php" ;// &REQUEST=GetFeature $cryptedPass = base64_encode(User::getLogin() . ":" . Crypt::decrypt($_SESSION['ADM_PASS_HASH'])); $uniqID = date("Y-m-d-H_i_s") . substr(md5(time()), 0, 6);// TODO: uniq id for every request // $cmd = "{$this->pathUrlActions}/{$path}/do_build.sh"; $cmd = "cd {$this->pathUrlActions}/{$path} && ant -S"; // ant -silent, -S print nothing but task outputs and build failures // ant -D= use value for given property // ant -propertyfile load all properties from file with -D properties taking precedence // TODO: mv to build.properties file @see https://dzone.com/tutorials/java/ant/ant-properties-file.html // ant -propertyfile build.properties $cmd .= " -DoutputFunctionUrl='{$outputFunctionUrl}'"; $cmd .= " -DantFunctionUrl='{$antFunctionUrl}'"; if( strlen($confirmAntfile) > 0 ) $cmd .= " -DconfirmAntfile={$confirmAntfile}"; if( strlen($confirmAntfileTarget) > 0 ) $cmd .= " -DconfirmAntfileTarget={$confirmAntfileTarget}"; $cmd .= " -DwebRootUrl='{$webRootUrl}'"; // $cmd .= " -Durl='{$testUrl}'"; nie mozna tego uzywac, bo nadpisuje property w funkcji build_get_wfs.xml $cmd .= " -DpasswordBase64Basic=\"{$cryptedPass}\""; $cmd .= " -Duuid=\"{$uniqID}\""; $cmd .= " -Dphp_session_id=\"" . session_id() . "\""; $cmd .= " -Dxpath={$pkField}"; $cmd .= " -Dxpath_value={$primaryKey}"; $cmd .= " -Dtemplate={$template}"; $cmd .= " -Dapi_url=".Request::getPathUri()."wfs-data.php"; //potrzebuje ten parametr do dzialania w AMS itp $cmd .= " -DtypeName=\"{$typeName}\""; if ($template) $cmd .= " {$template} "; $cmd .= " 2>&1"; $pathCmd = []; $pathCmd[] = '/opt/local/bin/ant'; $pathCmd[] = '/bin'; $pathCmd[] = '/usr/bin'; $pathCmd[] = '/usr/local/bin'; $pathCmd[] = '/opt/local/bin'; $pathCmd[] = '/sbin'; $pathCmd[] = '/usr/sbin'; $pathCmd[] = '/opt/local/sbin/skrypty'; $pathCmd[] = '/opt/local/var/macports/software'; $pathCmd[] = '/Applications/Server.app/Contents/ServerRoot/usr/bin'; $pathCmd[] = '/Applications/Server.app/Contents/ServerRoot/usr/sbin'; $cmd = 'export PATH=' . implode(':', $pathCmd) . "\n" . 'JAVA_HOME="/usr/bin/java"' . "\n" . 'MAVEN_OPTS="-Xms256m -Xmx512m"' . "\n" . $cmd; $useShellExec = true; if (User::isAdmin()) { echo UI::h('details', [], [ UI::h('summary', [ 'style' => "padding:3px 8px;border:1px solid #ccc;background-color:#282c34;color:#de6b74;font-size:small" ], "DBG: command"), UI::h('div', [ 'style' => "padding:12px; background:#282c34;" ], [ UI::h('pre', [], $cmd), ]), ]); } if ($useShellExec) $out = shell_exec($cmd); else V::exec($cmd, $out, $ret); DBG::log([ 'msg'=>"cmd and returns({$ret})", 'output'=>$out, 'cmd'=>str_replace(APP_PATH_ROOT, 'SE', $cmd) ]); if (empty($out)) throw new Exception("Empty output"); if ($useShellExec) $out = explode("\n", $out); $outputType = 'HTML'; $html = []; $startRead = false; foreach ($out as $line) { if (!$startRead) { if ('OUTPUT__TYPE__XML' == $line) $outputType = 'XML'; if ('OUTPUT__TYPE__HTML' == $line) $outputType = 'HTML'; if ('OUTPUT__START' == $line) { $startRead = true; continue; } } else { if ('"container", 'style'=>"padding:12px; border:1px solid #ddd"], $html); } } } catch (Exception $e) { UI::alert('danger', $e->getMessage()); DBG::log($e); } UI::endContainer(); UI::dol(); } }