From e99ee9945e005a58f83cecf1f19933e1504b3266 Mon Sep 17 00:00:00 2001 From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch> Date: Tue, 14 Nov 2023 16:26:10 +0100 Subject: [PATCH] split project class into gui and non gui --- public_html/deployment/classes/base.class.php | 4 + .../deployment/classes/project.class.php | 1803 +---------------- .../deployment/classes/project_gui.class.php | 1713 ++++++++++++++++ .../deployment/classes/projectlist.class.php | 4 +- public_html/deployment/pages/act_accept.php | 4 +- public_html/deployment/pages/act_build.php | 4 +- public_html/deployment/pages/act_delete.php | 4 +- public_html/deployment/pages/act_deploy.php | 4 +- public_html/deployment/pages/act_overview.php | 4 +- public_html/deployment/pages/act_phase.php | 4 +- public_html/deployment/pages/act_setup.php | 10 +- 11 files changed, 1773 insertions(+), 1785 deletions(-) create mode 100644 public_html/deployment/classes/project_gui.class.php diff --git a/public_html/deployment/classes/base.class.php b/public_html/deployment/classes/base.class.php index 0a647f27..cefb6605 100644 --- a/public_html/deployment/classes/base.class.php +++ b/public_html/deployment/classes/base.class.php @@ -9,6 +9,10 @@ require_once 'user.class.php'; */ class base { + /** + * logged in user + * @var object + */ var $oUser=false; /** diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php index a7806859..818cb762 100644 --- a/public_html/deployment/classes/project.class.php +++ b/public_html/deployment/classes/project.class.php @@ -5,7 +5,7 @@ define("OPTION_NONE", -1); require_once __DIR__.'/../inc_functions.php'; require_once 'base.class.php'; -require_once 'htmlguielements.class.php'; + require_once 'messenger.class.php'; // plugins @@ -38,43 +38,37 @@ class project extends base { * configuration ($aConfig in the config file) * @var array */ - private $_aConfig = array(); + protected $_aConfig = array(); /** * configuration of the project (= $aProjects[ID] in the config file) * @var array */ - private $_aPrjConfig = array(); + protected $_aPrjConfig = array(); /** * version infos of all phases * @var array */ - private $_aData = array(); - - /** - * existing branches and tags - * @var array - */ - private $_aVcsBranches = array(); + protected $_aData = array(); /** * existing versions in the archive dir * @var array */ - private $_aVersions = array(); + protected $_aVersions = array(); /** * output file to fetch processing content with ajax request * @var string */ - private $_sProcessTempOut = false; + protected $_sProcessTempOut = false; /** * places of version infos in each deployment phase * @var array */ - private $_aPlaces = array( + protected $_aPlaces = array( "onhold" => "Queue", "ready2install" => "Puppet", "deployed" => "Installiert", @@ -84,7 +78,7 @@ class project extends base { * collector for returncodes of multiple exec calls * @var int */ - private $_iRcAll = 0; + protected $_iRcAll = 0; /** @@ -97,7 +91,7 @@ class project extends base { * object to access a version control, .e. git * @var object */ - private $_oVcs = false; + protected $_oVcs = false; /** * object for rollout @@ -105,7 +99,7 @@ class project extends base { */ public $oRolloutPlugin = false; - private $_sBranchname = false; + protected $_sBranchname = false; /** * send messages @@ -146,7 +140,7 @@ class project extends base { * @param string $sLevel warnlevel of the given message * @return bool */ - private function log($sMessage, $sLevel = "info") { + protected function log($sMessage, $sLevel = "info") { global $oCLog; return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " . $sMessage, $sLevel); } @@ -156,7 +150,7 @@ class project extends base { * @param string $sMessage * @return boolean */ - private function _sendMessage($sMessage){ + protected function _sendMessage($sMessage){ $aConfig=array(); if (array_key_exists('messenger', $this->_aPrjConfig) @@ -207,7 +201,7 @@ class project extends base { * read default config file * @return boolean */ - private function _readConfig() { + protected function _readConfig() { global $aConfig; $this->_aConfig = $aConfig; return true; @@ -217,7 +211,7 @@ class project extends base { * validate config data * @return boolean */ - private function _verifyConfig() { + protected function _verifyConfig() { if (!is_array($this->_aPrjConfig) || !count($this->_aPrjConfig)){ // die(t("class-project-error-no-config")); throw new Exception(t("class-project-error-no-config")); @@ -273,7 +267,7 @@ class project extends base { * @param string $sCommand * @return string */ - private function _execAndSend($sCommand, $bFlush = false) { + protected function _execAndSend($sCommand, $bFlush = false) { $this->log(__FUNCTION__ . " start"); $sReturn = ''; $bUseHtml = $_SERVER ? true : false; @@ -354,7 +348,7 @@ class project extends base { * @param string $sAction project action * @param string $sLoglevel loglevel */ - private function _logaction($sMessage, $sAction = "", $sLoglevel = "info") { + protected function _logaction($sMessage, $sAction = "", $sLoglevel = "info") { require_once("actionlog.class.php"); $oLog = new Actionlog($this->_aConfig["id"]); $oLog->add($sMessage, (__CLASS__ . "->" . $sAction), $sLoglevel); @@ -364,7 +358,7 @@ class project extends base { // GETTER // ---------------------------------------------------------------------- - private function _getConfigFile($sId) { + protected function _getConfigFile($sId) { if (!$sId) { die(t("class-project-error-_getConfigFile-requires-id")); } @@ -375,7 +369,7 @@ class project extends base { * get a full ath for temp directory (for a build) * @return string */ - private function _getTempDir() { + protected function _getTempDir() { return $s = $this->_getBuildDir() . '/' . $this->_aPrjConfig["fileprefix"] . "_" . date("Ymd-His"); } @@ -383,7 +377,7 @@ class project extends base { * get full path where the project builds are (a build setes a subdir) * @return string */ - private function _getBuildDir() { + protected function _getBuildDir() { return $this->_aConfig['buildDir'] . '/' . $this->_aConfig["id"]; } @@ -391,7 +385,7 @@ class project extends base { * get full path where the project default files are * @return type */ - private function _getDefaultsDir() { + protected function _getDefaultsDir() { $s = $this->_aConfig['buildDefaultsDir'] . '/' . $this->_aConfig["id"]; return file_exists($s) ? $s : false; } @@ -402,7 +396,7 @@ class project extends base { * @param string $sPlace one of onhold|ready2install|deployed * @return string */ - private function _getFileBase($sPhase, $sPlace) { + protected function _getFileBase($sPhase, $sPlace) { if (!array_key_exists($sPhase, $this->_aConfig["phases"])) { die(sprintf(t("class-project-error-wrong-phase"), $sPhase)); } @@ -441,7 +435,7 @@ class project extends base { * @param string $sPlace one of onhold|ready2install|deployed * @return string */ - private function _getInfofile($sPhase, $sPlace) { + protected function _getInfofile($sPhase, $sPlace) { $sBase = $this->_getFileBase($sPhase, $sPlace); return $sBase ? $sBase . '/' . $this->_aPrjConfig["fileprefix"] . '.json' : false; } @@ -452,7 +446,7 @@ class project extends base { * @param string $sPlace one of onhold|ready2install|deployed * @return string */ - private function _getPackagefile($sPhase, $sPlace) { + protected function _getPackagefile($sPhase, $sPlace) { $sBase = $this->_getFileBase($sPhase, $sPlace); return $sBase ? $sBase . '/' . $this->_aPrjConfig["fileprefix"] : false; } @@ -556,7 +550,7 @@ class project extends base { * @param string $sVersion version number of the build * @return string */ - private function _getArchiveDir($sVersion) { + protected function _getArchiveDir($sVersion) { if (!$sVersion) { die(t("class-project-error-_getArchiveDir-requires-id")); } @@ -571,7 +565,7 @@ class project extends base { * @param type $sTimestamp * @return array */ - private function _getArchiveInfos($sTimestamp) { + protected function _getArchiveInfos($sTimestamp) { if (!$sTimestamp) { die(t("class-project-error-_getArchiveInfos-requires-id")); } @@ -610,6 +604,7 @@ class project extends base { } /** + * TODO: REMOVE * make an http get request and return the response body * @param string $url * @return string @@ -696,7 +691,7 @@ class project extends base { * and a rollback ist possible or not * return array */ - private function _getVersionUsage() { + protected function _getVersionUsage() { $aVersionData = array(); $sLastVersion = false; if (!count($this->getVersions())) { @@ -743,10 +738,10 @@ class project extends base { /** * recursive delete - * @param type $dir + * @param string $dir directory to delete * @return type */ - private function _rmdir($dir) { + protected function _rmdir($dir) { foreach (scandir($dir) as $sEntry) { if (is_dir($dir . '/' . $sEntry) && $sEntry != '.' && $sEntry != '..') { $this->_rmdir($dir . '/' . $sEntry); @@ -1205,7 +1200,7 @@ class project extends base { /** * get list of remote branches and tags * @param bool $bIgnoreCache flag to ignore exiting cached data - * @return string|boolean + * @return array|boolean */ public function getRemoteBranches($bIgnoreCache=false) { $this->log(__FUNCTION__ . "($bIgnoreCache) start"); @@ -1220,95 +1215,7 @@ class project extends base { return false; } - /** - } - * get html form with selectr for remote branches - * @param string $sActiveBranchname force active branch name - * @param bool $bIgnoreCache flag to ignore exiting cached data - * @return string - */ - public function renderSelectRemoteBranches($sActiveBranchname = false, $bIgnoreCache=false) { - $this->log(__FUNCTION__."(sActiveBranchname = $sActiveBranchname, bIgnoreCache = ".($bIgnoreCache ? 'true' : 'false').") start"); - $aReturn = array(); - $aRadios = array(); - $bFoundActive = false; - $i = 0; - if (!$this->_oVcs) { - $this->_initVcs(); - } - require_once("formgen.class.php"); - if (!$sActiveBranchname) { - $sActiveBranchname = $this->_sBranchname; - } - if ($this->_oVcs) { - if (!method_exists($this->_oVcs, "getRemoteBranches")) { - // the version control class does not have this method - return ''; - } - foreach ($this->_oVcs->getRemoteBranches($bIgnoreCache) as $aBranch) { - $sBranch = $aBranch['name']; - $aRadios[$sBranch] = array( - 'value' => $sBranch, - 'label' => $aBranch['label'], - ); - // if no param was given the first branch will be marked - if (!$sActiveBranchname) { - $sActiveBranchname = $sBranch; - } - if ($sBranch == $sActiveBranchname) { - $bFoundActive = true; - // $aRadios[$sBranch]['checked'] = 'checked'; - $aRadios[$sBranch]['selected'] = 'selected'; - } else { - // for SELECT we need the onclick even on select element - // not on the option (Chrome) - // $aRadios[$sBranch]['onclick'] = 'document.getElementById(\'submitBranch\').click()'; - } - }; - } - // no branches were found - if (count($aRadios) == 0) { - return ''; - } - - $aForms = array( - 'frmSelectBranch' => array( - 'meta' => array( - 'method' => 'POST', - 'action' => '?', - 'id' => 'frmSelectBranch', - ), - 'validate' => array(), - 'form' => array( - 'branchname' => array( - 'inline' => true, - 'type' => 'select', - 'onchange' => 'document.getElementById(\'submitBranch\').click()', - 'name' => 'branchname', - 'label' => '<strong>' . t('branch-select') . '</strong>', - 'validate' => 'isastring', - 'options' => $aRadios, - ), - ), - ), - ); - - // submit to switch branches - only if a selection is available - if (count($aRadios) > 1 || !$bFoundActive) { - $aForms['frmSelectBranch']['form']['submitBranch'] = array( - 'type' => 'submit', - 'name' => 'btnsave', - 'onclick' => 'showModalMessage(\'' . t('branch-switch') . '\'); ', - 'label' => t("change"), - 'value' => $this->_oHtml->getIcon('sign-ok').t("change"), - ); - } - $oFrm = new formgen($aForms); - return $oFrm->renderHtml('frmSelectBranch') - . '<script>$("#submitBranch").hide();</script>'; - // return $oFrm->renderHtmlElement('dummy',$aFormData); - } /** * get current revision and log message from remote repo @@ -1337,7 +1244,7 @@ class project extends base { * init version control system (git, ...) * @return vcs-object */ - private function _initVcs() { + protected function _initVcs() { $this->log(__FUNCTION__ . " start"); if (!$this->_oVcs) { if (!$this->_aPrjConfig["build"]["type"]) { @@ -1396,7 +1303,7 @@ class project extends base { * get a flat array of all existing ssh keys * @return array */ - private function _getSshKeys() { + protected function _getSshKeys() { $aReturn = array(); foreach (glob($this->_aConfig["dataDir"] . "/sshkeys/*.pub") as $filename) { $aReturn[] = str_replace(".pub", "", basename($filename)); @@ -1410,7 +1317,7 @@ class project extends base { * @param string $sPhase phase * @return array */ - private function _getDeploytimes($sPhase) { + protected function _getDeploytimes($sPhase) { if (!$this->isActivePhase($sPhase)) { $sError = sprintf(t("class-project-warning-phase-not-active"), $sPhase); $this->_logaction($sError, __FUNCTION__, "error"); @@ -1431,7 +1338,7 @@ class project extends base { // SETTER // ---------------------------------------------------------------------- - private function _setProcessOutFile($sNewTempfile = false) { + protected function _setProcessOutFile($sNewTempfile = false) { if ($this->_sProcessTempOut && file_exists($this->_sProcessTempOut)) { unlink($this->_sProcessTempOut); } @@ -1446,7 +1353,7 @@ class project extends base { * * @return array */ - private function _ldapProjectSearch($sSearchFilter) { + protected function _ldapProjectSearch($sSearchFilter) { $aReturn = array(); require_once("ldap.class.php"); $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']); @@ -1576,7 +1483,7 @@ class project extends base { * @param type $sData * @return boolean */ - private function _TempFill($sData, $aActions = array()) { + protected function _TempFill($sData, $aActions = array()) { if (!$this->_sProcessTempOut) { return false; } @@ -1607,7 +1514,7 @@ class project extends base { * @param string $sTempDir optional; target dir to copy; default=false (=delete file) * @return boolean */ - private function _TempDelete($sTempDir=false) { + protected function _TempDelete($sTempDir=false) { if (!$this->_sProcessTempOut){ return false; } @@ -2595,1641 +2502,5 @@ class project extends base { return false; } - // ---------------------------------------------------------------------- - // RENDERING - // ---------------------------------------------------------------------- - - /** - * return html code for a div with background color based on a checksum of the given text - * @param string $sText text that is used for checksum; if false ist returns a gray - * @param string $sContent optional: text to show - * @return string - */ - private function _getChecksumDiv($sText, $sContent='') { - if ($sText){ - - // color ranges in decimal values for RGB from ... to - $iFgStart=60; $iFgEnd=160; - $iBgStart=200; $iBgEnd=250; - - // deivider: 3 digits of md5 will be extracted - $iFgDivider=16*16*16/($iFgEnd-$iFgStart); - $iBgDivider=16*16*16/($iBgEnd-$iBgStart); - - $sHash=md5($sText); - $sColor='' - . 'color: rgba(' - . ($iFgStart + round(hexdec(substr($sHash,0,3))/$iFgDivider)) . ',' - . ($iFgStart + round(hexdec(substr($sHash,3,3))/$iFgDivider)) . ',' - . ($iFgStart + round(hexdec(substr($sHash,6,3))/$iFgDivider)) . ',' - . '1' - . ');' - . 'background: rgba(' - . ($iBgStart + round(hexdec(substr($sHash,0,3))/$iBgDivider)) . ',' - . ($iBgStart + round(hexdec(substr($sHash,3,3))/$iBgDivider)) . ',' - . ($iBgStart + round(hexdec(substr($sHash,6,3))/$iBgDivider)) . ',' - . '1' - . ');' - ; - } else { - $sColor = "color: #888; background: #ccc;"; - } - return '<div style="' . $sColor . '; border-top: 3px solid; ">'.($sContent ? $sContent : ' ').'</div>'; - } - - /** - * generate css color based on a checksum of the given text - * @param string $sText text that is used for checksum - * @return string - */ - private function _getChecksumColor($sText, $sFormat = "hex", $fAlpha = 1.0) { - $sReturn = ''; - if ($sText){ - $sHash=md5($rssItem["feedtitle"]); - $iStartFg=100; - $iStartBg=220; - $sColor='' - . '' - . 'color: rgba(' - . ($iStartFg + round(hexdec(substr($sHash,0,2))/4)) . ',' - . ($iStartFg + round(hexdec(substr($sHash,2,2))/4)) . ',' - . ($iStartFg + round(hexdec(substr($sHash,4,2))/4)) - . ');' - . 'background: rgba(' - . ($iStartBg + round(hexdec(substr($sHash,0,2))/8)) . ',' - . ($iStartBg + round(hexdec(substr($sHash,2,2))/8)) . ',' - . ($iStartBg + round(hexdec(substr($sHash,4,2))/8)) - . ');' - ; - - $s = md5($sText); - $sRH = substr($s, 0, 2); - $sGH = substr($s, 2, 2); - $sBH = substr($s, 4, 2); - } else { - $sReturn = "background: #aaaaaa;"; - } - switch ($sFormat) { - case "rgba": - $sReturn = "background: rgba(" . hexdec($sRH) . ", " . hexdec($sGH) . ", " . hexdec($sBH) . ", " . $fAlpha . ")"; - break; - - default: - $sReturn = "background: #$sRH$sGH$sBH"; - break; - } - return $sReturn; - } - - /** - * get html code for the colored bar on top of each phase detail items - * @param string $sPhase phase of a project - * @param string $sPlace place in the given phase - * @return string - */ - private function _renderBar($sPhase, $sPlace) { - $aDataPhase = $this->getPhaseInfos($sPhase); - $aData = $aDataPhase[$sPlace]; - if (!array_key_exists("revision", $aData)) { - return false; - } - return $this->_getChecksumDiv($aData["revision"]); - } - - private function _renderHostsData($aData) { - $sReturn = ''; - if (array_key_exists('_hosts', $aData)) { - - // $sReturn.= print_r($aData['_hosts'], 1); - $sReturn.= '<div class="hosts">' - . '<br><strong>' . t('hosts') . ':</strong><br>' - ; - foreach ($aData['_hosts'] as $sHostname => $aHostinfos) { - $oUpdateDate = date("U", strtotime($aHostinfos['time'])); - $iAgeUpdate = round((date("U") - $oUpdateDate) / 60); - $sAge = $iAgeUpdate < 60 * 60 * 13 ? $iAgeUpdate . " min" : "??"; - - $sReturn.= '<div class="host">' - . $this->_getChecksumDiv( - $aHostinfos['_data']['revision'], - $this->_oHtml->getIcon('host').'<br>' . $sHostname - ) - . "($sAge)" - . '</div>' - ; - } - $sReturn.= '</div><div style="clear: both;"></div>'; - } - return $sReturn; - } - - /** - * get html code for list of hosts in a phase - * @param string $sPhase phase of a project - * @return string - */ - private function _renderHosts($sPhase) { - $aDataPhase = $this->getPhaseInfos($sPhase); - if (is_array($aDataPhase) && array_key_exists('deployed', $aDataPhase)) { - return $this->_renderHostsData($aDataPhase['deployed']); - } - return ''; - } - - /** - * get html code for list of files in a phase - * @param string $sPhase phase of a project - * @return string - */ - private function _renderFiles($sPhase) { - $sReturn = ''; - $aFiles = $this->getBuildfilesByPlace($sPhase, 'ready2install'); - if (!$aFiles || !$aFiles['filecount']) { - return ''; - } - $sReturn.='<strong>' . t("filelist") . '</strong> (' . $aFiles['filecount'] . '):<br>'; - foreach ($aFiles['files'] as $sFilename => $aData) { - $sReturn.='<div class="file file-' . $aData['type'] . ' fileext-' . $aData['extension'] . '" title="' . $sFilename . ' (' . $aData['type'] . ')">' - . $aData['icon'] . $sFilename - // . ' ('.$aData['type'].')' - . '</div>' - ; - } - $sReturn.='(' . $aFiles['totalsize-hr'] . ')'; - return $sReturn; - } - - /** - * return html code for current project errors by rendering a box per error in $this->_errors - * @return string - */ - public function renderErrorBoxes(){ - $sReturn=''; - if(count($this->_errors)){ - foreach($this->_errors as $sError){ - $sReturn.=$this->_oHtml->getBox("error", $sError); - } - } - return $sReturn; - } - /** - * render html for a colored link to any project action - * @param string $sFunction name of the action; one of accept|build|cleanup|deploy|new|overview|phase|rollback|setup - * @param string $sPhase current phase where to place the link - * @return string - */ - public function renderLink($sFunction, $sPhase = false, $sVersion = false) { - $sFirst = $this->getNextPhase(); - $sNext = $this->getNextPhase($sPhase); - $aLinkdata = array( - 'default' => array('class' => ''), - 'accept' => array('class' => $sNext, - 'hint' => sprintf(t("accept-hint"), $sPhase, $sNext), - 'label' => t('accept'), - ), - 'build' => array('class' => $sFirst, - 'hint' => sprintf(t("build-hint"), $sFirst), - 'label' => t('build'), - 'role' => 'buildProject' - ), - 'cleanup' => array('class' => ''), - 'deploy' => array('class' => $sPhase, - 'hint' => sprintf(t("deploy-hint"), $sPhase), - 'label' => t('deploy'), - ), - 'new' => array( - 'hint' => t("new-project-hint"), - 'label' => t('new-project'), - ), - 'overview' => array('class' => '', - 'hint' => t('menu-project-home') . ' [' . $this->getLabel() . ']', - 'label' => $this->getLabel() - ), - 'phase' => array('icon' => $this->_oHtml->getIcon('phase'), 'class' => $sPhase, - 'hint' => sprintf(t('phase-details-hint'), $sPhase), - 'label' => t('phase-details') - ), - 'rollback' => array('class' => $sPhase, - 'hint' => sprintf(t('rollback-hint'), $sPhase, $sVersion), - 'label' => t('rollback') - ), - 'setup' => array('class' => $sPhase, - 'hint' => sprintf(t('setup-hint'), $sPhase, $sVersion), - 'label' => t('setup') - ), - ); - /* - if (!$this->oUser->hasRole("project-action-$sFunction")){ - // $sClass .= ' disabled'; - // return '<span title="no permission [project-action-'.$sFunction.']">[ ]</span>'; - } - * - */ - // fuer wen ist der Link - $sRole = ''; - $sOnMouseover = ''; - $sOnMouseout = ''; - switch($sFunction){ - case 'accept'; - $sRole = 'developer'; - if ($sNext == "live") { - $sRole = 'pl'; - // $aLinkdata[$sFunction]['icon']='glyphicon glyphicon-star'; - } - $sOnMouseover = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'; - $sOnMouseout = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');'; - break; - case 'build'; - $sRole = 'developer'; - $sOnMouseover = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'; - $sOnMouseout = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');'; - break; - case 'deploy'; - $sRole = 'developer'; - $sOnMouseover = '$(\'.td-phase-' . $sPhase . '.td-place-ready2install.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');' - .'$(\'.td-phase-' . $sPhase . '.td-place-deployed.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');' - ; - $sOnMouseout = '$(\'.td-phase-' . $sPhase . '.td-place-ready2install.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');' - .'$(\'.td-phase-' . $sPhase . '.td-place-deployed.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');' - ; - break; - } - - // $sClass = $sPhase; - $sIconClass = (array_key_exists($sFunction, $aLinkdata)) ? $aLinkdata[$sFunction]['icon'] : $aLinkdata['default']['icon']; - $sHint = ( - array_key_exists($sFunction, $aLinkdata) && array_key_exists("hint", $aLinkdata[$sFunction]) - ) ? $aLinkdata[$sFunction]['hint'] : ""; - $sLabel = ( - array_key_exists($sFunction, $aLinkdata) && array_key_exists("label", $aLinkdata[$sFunction]) - ) ? $aLinkdata[$sFunction]['label'] : $sFunction; - $sClass = ( - array_key_exists($sFunction, $aLinkdata) && array_key_exists("class", $aLinkdata[$sFunction]) - ) ? $aLinkdata[$sFunction]['class'] : ''; - if ($sRole) { - $sClass .= " role role" . $sRole; - } - - $sLink = "/deployment/" . ($this->_aConfig["id"] ? $this->_aConfig["id"] : 'all/setup') . "/"; - if ($sFunction != "overview") { - $sLink.="$sFunction/"; - } - if ($sPhase) { - $sLink.="$sPhase/"; - } - if ($sVersion) { - $sLink.="$sVersion/"; - } - if (!$this->oUser->hasPermission("project-action-$sFunction")) { - // $sClass .= ' disabled'; - return '<span class="btn disabled btn-default" title="no permission [project-action-' . $sFunction . '] for user [' . $this->oUser->getUsername() . ']"><i class="' . $sIconClass . '"></i> ' . $sLabel . '</span>'; - } - - return $this->_oHtml->getLinkButton(array( - 'href' => $sLink, - 'title' => $sHint, - 'class' => 'btn btn-default ' . $sClass, - 'type' => $sFunction, - 'onmouseover' => $sOnMouseover, - 'onmouseout' => $sOnMouseout, - 'label' => $sLabel, - )); - // return '<a href="' . $sLink . '" ' . $sOnMouseover . ' title="' . $sHint . '" class="btn btn-default ' . $sClass . '"><i class="' . $sIconClass . '"></i> ' . $sLabel . '</a>'; - } - - /** - * render html for the project overview; it shows the defined phases for - * the project as a table - * @return type - */ - public function renderPhaseInfo() { - $sRow1 = false; - $sRow2 = false; - foreach ($this->getActivePhases() as $sPhase) { - $sRow1.='<th class="' . $sPhase . '">' . $sPhase . '</th>'; - $sRow2.='<td class="' . $sPhase . '">' - . t('url') . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>' - . '<br>' . t('deploytimes') . ':<br>'; - if (count($this->_getDeploytimes($sPhase))) { - $sRow2.=implode("<br>", $this->_getDeploytimes($sPhase)); - } else { - $sRow2.=t('deploytimes-immediately'); - } - $sRow2.='<br>' . $this->renderLink("phase", $sPhase) - . $this->_renderHosts($sPhase) - . '<br>' - . $this->_renderFiles($sPhase) - . '</td>'; - } - return '<table><thead><tr>' . $sRow1 . '</tr></thead><tbody><tr>' . $sRow2 . '</tr></tbody></table>'; - } - - /** - * render html for a place of a phase - * @param string $sPhase phase - * @param string $sPlace name of the place; one of onhold|ready2install|deployed - * @param bool $bActions draw action links (deploy, accept) on/ off - * @param bool $bLong use long variant to display infos? - * @return string|boolean - */ - public function renderPhaseDetail($sPhase, $sPlace, $bActions = true, $bLong = true) { - - if (!$sPhase) { - return false; - } - if (!$sPlace) { - return false; - } - if (!$this->isActivePhase($sPhase)) { - return false; - } - if (!array_key_exists($sPlace, $this->_aPlaces)) { - return false; - } - - $sReturn = false; - $aDataPhase = $this->getPhaseInfos($sPhase); - $aData = $aDataPhase[$sPlace]; - // foreach($aDataPhase[$sPlace] as $aData) { - if (array_key_exists("ok", $aData) && array_key_exists("version", $aData)) { - // TODO: getChecksumDiv anhand der Repo-Versionsnummer - dann kann man beim build auch die Farbe mit dem Repo HEAD vergleichen - // time - $sDateFormat = "d.m.Y H:i"; - $oPkgDate = date("U", strtotime($aData["date"])); - /* - $iAge=date("U")-$oPkgDate; - $sAgeClass=""; - if ($iAge< 60*60*24*3){ - $sAgeClass="last1d"; - } - if ($iAge< 60*60){ - $sAgeClass="last1h"; - } - */ - - if ($bLong) { - // long display of the revision - // $sJsonUrl = $this->_getInfofile($sPhase, $sPlace); - $sReturn .=$this->_getChecksumDiv( - $aData["revision"], - $this->_oHtml->getIconByType('calendar') .' ' . date($sDateFormat, $oPkgDate) - . $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aData["branch"] . '<br>' - . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aData["revision"]) . '<br>' - . $this->_oHtml->getIconByType('comment') . t('commitmessage') . ':<br>' - ) - . '<pre>' . strip_tags($aData["message"], '<br>') . '</pre>' - // . '<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sJsonUrl . '">' . $sJsonUrl . '</a><br>' - ; - if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) { - $sUrl = $this->_aPrjConfig["phases"][$sPhase]["url"]; - $sReturn.=$this->_oHtml->getIconByType('link-extern') . ' '. t('url') . ': <a href="' . $sUrl . '">' . $sUrl . '</a><br>'; - } - } else { - $sReturn .= $this->_getChecksumDiv( - $aData["revision"], - $this->_oHtml->getIconByType('calendar') .' ' . date($sDateFormat, $oPkgDate) - ); - if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) { - $sMore = $this->_oHtml->getIconByType('link-extern').' ' - . t('url') - . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>'; - } - - $sReturn.=' ' . $this->renderInfoLink( - $aData, array( - 'title' => $this->getLabel() . " :: $sPhase :: $sPlace", - 'more' => $sMore, - ) - ); - } - - switch ($sPlace) { - case "onhold": - if (array_key_exists("phases", $this->_aConfig) && array_key_exists($sPhase, $this->_aConfig["phases"])) { - // $sReturn .= print_r($this->_aConfig["phases"][$sPhase], true); - if (count($this->_getDeploytimes($sPhase))) { - $sReturn .= '<br>'.$this->_oHtml->getIcon('time').t('deploytimes') . ':<br>' - . implode("<br>", array_values($this->_getDeploytimes($sPhase))) - . '<br>'; - } - if ($bActions) { - $sReturn .= ' ' . $this->renderLink("deploy", $sPhase); - } - } - break; - - case "ready2install": - break; - - case "deployed": - if ($bActions && $this->canAcceptPhase($sPhase)) { - $sReturn .= ' ' . $this->renderLink("accept", $sPhase); - } - break; - default: - break; - } - // $this->_getChecksumDiv($aData["revision"]) - } else { - if (array_key_exists("error", $aData)) { - $sReturn.='' - . $this->renderInfoLink(array('error' => $aData["error"]), array()) - ; - } else if (array_key_exists("warning", $aData)) { - $sReturn.= '<div class="warning">'.$this->_oHtml->getIcon('sign-info'). t('warning') . ':<br>' . $aData["warning"] . '</div>'; - } else { - return false; - // $sReturn.= t('empty'); - } - } // if - // } // for - return $sReturn; - } - - /** - * render html for a row with td for all places (first row) - * @param string $sPhase phase (just needed for coloring) - * @return string - */ - public function renderPlacesAsTd($sPhase) { - $sRow1 = ''; - foreach (array_keys($this->_aPlaces) as $sPlace) { - $sRow1.='<td class="' . $sPhase . ' ' . $this->_aConfig["id"] . ' tdphase">' . t($sPlace) . '</td>'; - } - return $sRow1; - } - - /** - * render html for a row with td for all places of a phase - * @param string $sPhase phase - * @param bool $bActions draw action links (deploy, accept) on/ off - * @param bool $bLong use long variant to display infos? - * @return string|boolean - */ - public function renderAllPhaseDetails($sPhase, $bActions = true, $bLong = true) { - if (!$sPhase) { - return false; - } - if (!$this->isActivePhase($sPhase)) { - return ' - <td class="td-phase-' . $sPhase . ' td-phase-inactive ' . $this->_aConfig["id"] . '" colspan="' . count($this->_aPlaces) . '"> - <div class="versioninfo center inactive">' . $this->_oHtml->getIcon('sign-info').t('inactive') . '</div> - </td>'; - } - $sRow2 = false; - - $aRows = array(); - $sLastPlace = ''; - - foreach (array_keys($this->_aPlaces) as $sPlace) { - $aRows[$sPlace] = $this->renderPhaseDetail($sPhase, $sPlace, $bActions, $bLong); - - // generate ">>" sign for lastly generated td - if ($sLastPlace && array_key_exists("version", $this->_aData["phases"][$sPhase][$sLastPlace]) - && array_key_exists("version", $this->_aData["phases"][$sPhase][$sPlace]) - && $this->_aData["phases"][$sPhase][$sLastPlace]["version"] == $this->_aData["phases"][$sPhase][$sPlace]["version"] - && !$bLong - ) { - $aRows[$sLastPlace] = $this->_renderBar($sPhase, $sPlace) . "»"; - } - $sLastPlace = $sPlace; - } - - foreach (array_keys($this->_aPlaces) as $sPlace) { - $sRow2.='<td class=" td-phase-'.$sPhase.' td-place-'.$sPlace.' td' . $this->_aConfig["id"] . '">' . $aRows[$sPlace] . '</td>'; - } - return $sRow2; - } - - /** - * return html code for the installed version in the repository - * @param boolean $bRefresh optional: refresh flag; default: use cached information - * @return string - */ - public function renderRepoInfo($bRefresh=false) { - $sReturn = ""; - switch ($this->_aPrjConfig["build"]["type"]) { - case "git": - - $aRepodata = $this->getRepoRevision($bRefresh); - if (array_key_exists("revision", $aRepodata)) { - $sReturn.=$this->_getChecksumDiv($aRepodata["revision"], - $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . (array_key_exists("branch", $aRepodata) ? $aRepodata["branch"] : '-') . '<br>' - . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aRepodata["revision"]) . '<br>' - . $this->_oHtml->getIconByType('comment') . t('commitmessage') . ':<br>' - ) - ."<pre>" . strip_tags($aRepodata["message"], '<br>') . "</pre>"; - } else { - $sReturn .= $this->_oHtml->getBox("error", sprintf(t('class-project-error-no-repoinfo'), $aRepodata["error"])) - . $this->renderLink("setup") . '<br>'; - } - - break; - - default: - $sReturn .= $this->_oHtml->getBox("error", sprintf(t('class-project-error-wrong-buildtype'), $this->_aPrjConfig["build"]["type"])); - } - if (array_key_exists("url", $this->_aPrjConfig["build"])) { - $sReturn.=t('repository-url') . ': ' . $this->_aPrjConfig["build"]["url"] . '<br>'; - } - if (array_key_exists("webaccess", $this->_aPrjConfig["build"])) { - $sReturn.=t('repository-access-browser') . ':<br><a href="' . $this->_aPrjConfig["build"]["webaccess"] . '">' . $this->_aPrjConfig["build"]["webaccess"] . '</a><br>'; - } - return $sReturn; - } - - /** - * get html code for a link to the commit - * (works for guithub and gitlab instances) - * - * @param string $sRevision - * @return string - */ - public function _renderRevision($sRevision) { - $sUrl = str_replace('/tree/master', '', $this->_aPrjConfig["build"]["webaccess"]) . '/commit/' . $sRevision; - return '<a href="' . $sUrl . '">' . $sRevision . '</a>'; - return $sUrl; - } - - /** - * render html code for info link that shows popup with metadata on mouseover - * @param array $aInfos metainfos of the package (from json file) - * @param array $aOptions options - * title - tile in popover; default: empty - * label - link label; default: empty (results in Infos|ERROR) - * more - additional infos in popover; default: empty - * hpos - horizontal position; one of left|right; default: right - * @return string - */ - public function renderInfoLink($aInfos, $aOptions = array()) { - $sReturn = ''; - $bIsError = false; - $this->_oHtml = new htmlguielements(); - - $sInfos=''; - $sTitle=''; - if (array_key_exists("title", $aOptions) && $aOptions["title"]) { - $sTitle.=$aOptions["title"]; - } - if (array_key_exists("ok", $aInfos)) { - $sLinktitle = t('infos'); - if (array_key_exists("message", $aInfos)) { - $sInfos.=$this->_getChecksumDiv($aInfos["revision"], - $this->_oHtml->getIconByType('calendar') . t('build-from') . ' ' . date("d.m.Y H:i:s", strtotime($aInfos["date"])) . '<br>' - . $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aInfos["branch"] . '<br>' - . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aInfos["revision"]) . '<br>' - . $this->_oHtml->getIconByType('comment') . t('commitmessage') . ': ' - ) - . '<pre>' . strip_tags($aInfos["message"], '<br>') . '</pre>'; - if (array_key_exists("more", $aOptions)) { - $sInfos.=$aOptions["more"]; - } - } - } else { - $bIsError = true; - if (!$sTitle) { - $sTitle.=' ' . t('error'); - } - $sLinktitle = t('error'); - $sInfos = $aInfos["error"]; - } - $sInfos.=$this->_renderHostsData($aInfos); - - if (array_key_exists("label", $aOptions) && $aOptions["label"]) { - $sLinktitle.=$aOptions["label"]; - } - - // render html - $sId = 'info' . md5($sInfos); - $sReturn = '<a href="#" class="btn ' . ($bIsError ? 'btn-danger' : 'btn-default') . '" title="" onclick="showIdAsModalMessage(\'' . $sId . '\'); return false;">' - // . '<i class="fa fa-info"></i> ' - . $sLinktitle - . '</a><div id="' . $sId . '" style="display: none;" '; - if (array_key_exists("hpos", $aOptions)) { - $sReturn.=' class="' . $aOptions["hpos"] . '"'; - } - $sReturn.='>'; - - if ($sTitle) { - $sReturn.='<span class="title">' . $sTitle . '</span><br><br>'; - } - - $sReturn.=$sInfos . '</div>'; - - if ($bIsError) { - // $sReturn = '<div class="error">' . $sReturn . '</div>'; - } - - return $sReturn; - } - - /** - * return html code for a list of all built packages and their usage - * @return string - */ - public function renderVersionUsage() { - $sReturn = false; - $sRowHead1 = false; - $sRowHead2 = '<td></td>'; - - $aAllVersions = $this->_getVersionUsage(); - if (!count($aAllVersions)) { - return $this->_oHtml->getBox("info", t('class-project-info-no-package')); - } - - foreach ($this->getActivePhases() as $sPhase) { - $sRowHead1.='<th class="' . $sPhase . '" colspan="' . (count($this->_aPlaces) + 1) . '">' . $sPhase . '</th>'; - $sRowHead2.='<td></td>' . $this->renderPlacesAsTd($sPhase); - } - - krsort($aAllVersions); - foreach ($aAllVersions as $sVersion => $aData) { - $sReturn.='<tr>'; - - $sInfos = $this->renderInfoLink($aData["info"], array('hpos' => 'left')); - $sReturn.='<td>' - . $this->_getChecksumDiv( - $aData['info']['revision'], - $this->_oHtml->getIconByType('calendar') . t('build-from') . ': ' . $sVersion .'<br>' - . $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aData['info']["branch"] . '<br>' - . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aData['info']["revision"]) . '<br>' - ) - . '</td><td>' - . ' ' . $sInfos . ' ' - . '</td>' - ; - - foreach ($this->getActivePhases() as $sPhase) { - $sTLine = ''; - $bCanRollback = $aData["rollback"][$sPhase]; - - // $sReturn.=$aData["rollback"][$sPhase] ? '<td>'.$this->renderLink("rollback", $sPhase, $sVersion).'</td>' : '<td>Rollback NOT possible</td>'; - // $sReturn.=$aData["rollback"][$sPhase] ? '<td> Y </td>' : '<td> N </td>'; - $sReturn.='<td> </td>'; - - foreach (array_keys($this->_aPlaces) as $sPlace) { - $bFound = false; - $sReturn.=$aData["usage"][$sPhase][$sPlace] - ? '<td class="' . $sPhase . '" style="text-align: center;">' - . $this->_getChecksumDiv($aData['info']['revision'], 'X') - . '</td>' - : '<td> </td>' - ; - } - } - $sReturn.='</tr>'; - } - - $sReturn = t('class-project-info-table-packages') . '<br><br>' - . '<table>' - . '<thead><tr><td>Version</td><td></td>' - . $sRowHead1 - . '</tr><tr><td>' - . $sRowHead2 - . '</tr></thead>' - . '<tbody>' - . $sReturn - . '</tbody>' - . '</table>'; - return $sReturn; - } - - /** - * render graphical overview of process (in project overview) - * @return string - */ - public function renderVisual() { - $sReturn = ''; - $sContinue = '<span style="font-size: 300%; color:#ace;">»»</span><br><br>'; - - $aBranches=$this->getRemoteBranches(); - if(!is_array($aBranches)){ - return t("project-setup-incomplete"); - } - - $sRepoBar = ''; - /* - Speedup: - - $aRepodata = $this->getRepoRevision(); - if (array_key_exists("revision", $aRepodata)) { - $sRepoBar = $this->_getChecksumDiv($aRepodata["revision"]); - } else { - $sRepoBar = '<span class="error">' . t("error") . '</span>'; - } - */ - - $sPackagebar = ''; - $aVersions = $this->_getVersionUsage(); - foreach ($aVersions as $sVersion => $aData) { - $sBar = $aData["info"]["revision"] ? $this->_getChecksumDiv($aData["info"]["revision"]) : ''; - $sPackagebar.='<span title="' . $sVersion . '" style="float: left; background:#eee; height: 3px; width:' . (100 / count($aVersions)) . '%">' . $sBar . ' </span>'; - } - - $sPhaseImg = ''; - $sLastPhase = ''; - foreach ($this->getActivePhases() as $sPhase) { - if ($sPhaseImg) { - $sAction = $sContinue; - if ($this->canAcceptPhase($sLastPhase)) { - $sAction .= $this->renderLink("accept", $sLastPhase); - } - $sPhaseImg.='<div class="action">' . $sAction . '</div>'; - } - $sLastPhase = $sPhase; - - $sFullbar = ''; - foreach (array_keys($this->_aPlaces) as $sPlace) { - $sFullbar.='<span title="' . $this->_aPlaces[$sPlace] . '" style="float: left; background:#eee; height: 3px; width:' . (100 / count($this->_aPlaces)) . '%">' . $this->_renderBar($sPhase, $sPlace) . ' </span>'; - } - // $sDetail = $sFullbar . '<br><a href="#h3phases" class="scroll-link">' . $sPhase . '</a>'; - $sDetail = $sFullbar . '<br>' . $sPhase; - - $sPhaseImg.=' - <div class="process ' . $sPhase . '"> - <div class="details">' . $sDetail . ' </div> - <div><img src="/deployment/images/process/bg_phase.png" alt="' . t("phase") . ' ' . $sPhase . '"></div> - </div>'; - } - $sReturn = ' - <div class="visualprocess"> - <div class="process box"> - <div class="title">' . $this->_oHtml->getIcon('repository') . t("versioncontrol") . '</div> - <div class="details"> - ' . $sRepoBar . '<br> - <!-- - <a href="#h3repo" class="scroll-link">' . t("repositoryinfos") . '</a><br> - --> - ' . t("repositoryinfos") . '<br> - ' . $this->_aPrjConfig["build"]["type"] . '</strong> ' . preg_replace('/.*\@(.*):.*/', '($1)', $this->_aPrjConfig["build"]["url"]) - . ': <strong title="' . t('branch-select') . '">' . count($aBranches) . '</strong>' - . '<br> - </div> - <div> - <img src="/deployment/images/process/bg_vcs.png" alt="' . t("versioncontrol") . '"> - </div> - </div> - - <div class="process"> - <div class="title"> </div> - <div class="action">' . $sContinue . t("build-hint-overview") . '<br><br>' . ($this->canAcceptPhase() ? $this->renderLink("build") : '') . '</div> - </div> - - - <div class="process box"> - <div class="title">' . $this->_oHtml->getIcon('package') . t("archive") . '</div> - <div class="details"> - ' . $sPackagebar . '<br> - <!-- - <a href="#h3versions" class="scroll-link">' . t("packages") . '</a><br> - --> - ' . t("packages") . '<br> - (<strong>' . count($this->_getVersionUsage()) . '</strong>) - </div> - <div><img src="/deployment/images/process/bg_archive.png" alt="' . t("archive") . '"></div> - </div> - - <div class="process"> - <div class="title"> </div> - <div class="action">'.$sContinue . sprintf(t("queue-hint-overview"), $this->getNextPhase()).'</div> - </div> - - <div class="process phases box"> - <div class="title">' . $this->_oHtml->getIcon('phase') . t("phases") . '</div> - ' . ($sPhaseImg ? $sPhaseImg : '<div class="process">' . t("none") . '</div>') . ' - </div> - </div> - '; - - return $sReturn; - } - - /** - * return html code for the setup form of an exsiting project - * @return string - */ - public function renderProjectSetup() { - if (!$this->oUser->hasPermission("project-action-setup")) { - return $this->oUser->showDenied(); - } - $sMessages = ''; - require_once ("formgen.class.php"); - - - $aSelectProjectGroup = array( - 'type' => 'select', - 'name' => 'projectgroup', - 'label' => t("projectgroup"), - 'options' => array( - OPTION_NONE => array( - 'label' => t('none'), - ), - '' => array( - 'label' => '- - - - - - - - - - - - - - - - - - - - ', - ), - ), - ); - foreach($this->_aConfig['projectgroups'] as $sGroupid=>$sGroupLabel){ - $bActive=$this->getProjectGroup() === $sGroupid; - $aSelectProjectGroup['options'][$sGroupid] = array( - 'label' => $sGroupLabel, - 'selected' => $bActive ? 'selected' : false, - ); - } - - $aSelectSlack = array( - 'type' => 'hidden', - 'name' => 'messenger[slack]', - 'value' => false, - ); - if ( - isset($this->_aConfig['messenger']['slack']['presets']) - && count($this->_aConfig['messenger']['slack']['presets']) - ) { - $aSelectSlack = array( - 'type' => 'select', - 'name' => 'messenger[slack]', - 'label' => t("messenger-slack"), - 'options' => array( - OPTION_NONE => array( - 'label' => t('none'), - ), - '' => array( - 'label' => '- - - - - - - - - - - - - - - - - - - - ', - ), - ), - ); - foreach($this->_aConfig['messenger']['slack']['presets'] as $sSlackUrl=>$aSlackCfg){ - $bActive=$this->_aPrjConfig['messenger']['slack'] === $sSlackUrl; - $aSelectSlack['options'][$sSlackUrl] = array( - 'label' => array_key_exists('label', $aSlackCfg) ? $aSlackCfg['label'] : $sSlackUrl, - 'selected' => $bActive ? 'selected' : false, - ); - } - - } - // ---------- Build plugins - /* - - $aPluginsBuild = array( - 'select' => array( - 'type' => 'checkbox', - 'name' => 'build[enabled_build_plugins]', - 'label' => t("build-plugins"), - 'options' => [], - ), - // 'project-config' => '', - ); - foreach (array_keys($this->getConfiguredPlugins('build')) as $sPluginName){ - - $sPluginFile=$this->_getPluginFilename('build', $sPluginName); - $TmpRolloutPlugin = false; - $sMyClassname='build_'. $sPluginName; - if(file_exists($sPluginFile)){ - try{ - include_once $this->_getPluginFilename('build', $sPluginName); - $TmpRolloutPlugin = new $sMyClassname([]); - echo "FOUND $sMyClassname<br>"; - $aPluginsBuild['select']['options'][$sPluginName]=array( - 'label' => $TmpRolloutPlugin->getName(), - 'checked' => $bActive, - // 'onclick' => '$(\'.'.$sMyDivClass.'\').hide(); $(\'.' . $sMyDivClassActive . '\').show();', - ); - } catch (Exception $ex) { - - } - } else { - $aRollout['project-select']['options'][$sPluginName]=array( - 'label' => 'not found: <span class="error">' . $sMyClassname . '</span>', - 'checked' => false, - 'disabled' => "disabled", - ); - - - } - } - echo '<pre>'; print_r($aPluginsBuild); die(__METHOD__); - */ - - // ---------- /Build plugins - - // ---------- Rollout plugins - $aRollout = array( - 'project-select' => array( - 'type' => 'radio', - 'name' => 'deploy[enabled_rollout_plugin]', - 'label' => t("deploy-rollout-plugin"), - ), - 'project-config' => '', - ); - foreach (array_keys($this->getConfiguredPlugins('rollout')) as $sPluginName){ - - $sPluginFile=$this->_getPluginFilename('rollout', $sPluginName); - $TmpRolloutPlugin = false; - $sMyClassname='rollout_'. $sPluginName; - $sMyDivId='rollout-'. $sPluginName.'-config'; - $sMyDivClass='rolloutconfigdiv'; - $sMyDivClassActive='rolloutconfigdiv-'. $sPluginName; - $bActive=$sPluginName === $this->oRolloutPlugin->getId(); - - if(file_exists($sPluginFile)){ - try{ - include_once $this->_getPluginFilename('rollout', $sPluginName); - $TmpRolloutPlugin = new $sMyClassname(array( - 'lang'=>$this->_aConfig['lang'], - 'phase'=>false, - 'globalcfg'=>$this->_aConfig['plugins']['rollout'][$sPluginName], - 'projectcfg'=>$this->_aPrjConfig, - )); - $aRollout['project-select']['options'][$sPluginName]=array( - 'label' => $TmpRolloutPlugin->getName(), - 'checked' => $bActive, - 'onclick' => '$(\'.'.$sMyDivClass.'\').hide(); $(\'.' . $sMyDivClassActive . '\').show();', - ); - - $aRollout['project-config'].='' - . '<div id="'.$sMyDivId.'" class="'.$sMyDivClass.' '.$sMyDivClassActive.'"' - . ($bActive ? '' : 'style="display: none;"' ) - . '>' - . $TmpRolloutPlugin->renderFormdata4Project() - . '</div>' - ; - - // generate form firlds for each phase - foreach(array_keys($this->getPhases()) as $sMyPhase){ - $aRollout[$sMyPhase].='' - . '<div id="'.$sMyDivId.'-'.$sMyPhase.'" class="'.$sMyDivClass.' '.$sMyDivClassActive.'"' - . ($bActive ? '' : 'style="display: none;"' ) - . '>' - . $TmpRolloutPlugin->renderFormdata4Phase($sMyPhase) - . '</div>' - ; - } - } catch (Exception $ex) { - - } - } else { - $aRollout['project-select']['options'][$sPluginName]=array( - 'label' => 'not found: <span class="error">' . $sMyClassname . '</span>', - 'checked' => false, - 'disabled' => "disabled", - ); - - - } - } - // ---------- /Rollout plugins - - $aForemanHostgroups = false; - $iForemanHostgroupDefault = false; - $sForemanHostgroupDefault = false; - if (array_key_exists('foreman', $this->_aConfig)) { - // echo '<pre>' . print_r($this->_aPrjConfig, 1) . '</pre>'; - $iForemanHostgroupDefault = (int) $this->_aPrjConfig['deploy']['foreman']['hostgroup']; - require_once('foremanapi.class.php'); - $oForeman = new ForemanApi($this->_aConfig['foreman']); - // $oForeman->setDebug(1); - // $oForeman->selfcheck(); die(__FUNCTION__); - - $aForemanHostgroups = $oForeman->read(array( - 'request' => array( - array('hostgroups'), - // array('operatingsystems',4), - ), - 'response' => array( - 'id', 'title' - ), - )); - $aSelectForemanGroups = array( - 'type' => 'select', - 'name' => 'deploy[foreman][hostgroup]', - 'label' => $this->_oHtml->getIcon('foreman') . t("foreman-hostgroup"), - 'options' => array( - OPTION_NONE => array( - 'label' => t('none'), - ), - '' => array( - 'label' => '- - - - - - - - - - - - - - - - - - - - ', - ), - ), - ); - if ($aForemanHostgroups && count($aForemanHostgroups)) { - foreach ($aForemanHostgroups as $aItem) { - $bActive=$iForemanHostgroupDefault === (int) $aItem['id']; - $aSelectForemanGroups['options'][$aItem['id']] = array( - 'label' => $aItem['title'], - 'selected' => $bActive ? 'selected' : false, - ); - $sForemanHostgroupDefault = $bActive ? $aItem['title'] : $sForemanHostgroupDefault; - } - } - } - - - $i = 0; - - $aPrefixItem = count($this->getVersions()) ? - array( - 'type' => 'markup', - 'value' => '<div class="form-group"> - <label class="col-sm-2">' . t('fileprefix') . '</label> - <div class="col-sm-10"> - <input id="inputprefix" type="hidden" name="fileprefix" value="' . $this->_aPrjConfig["fileprefix"] . '"> - ' . $this->_aPrjConfig["fileprefix"] . ' - </div></div> - ', - ) : array( - 'type' => 'text', - 'name' => 'fileprefix', - // 'disabled' => 'disabled', - 'label' => t('fileprefix-label'), - 'value' => $this->_aPrjConfig["fileprefix"], - 'required' => 'required', - 'validate' => 'isastring', - 'pattern' => '[a-z0-9\-_]*', - 'size' => 100, - 'placeholder' => '', - ); - - // detect access to repo url - $aBranches=$this->getRemoteBranches(); - // $aRepodata = $this->getRepoRevision(); - - // if (is_array($aRepodata) && array_key_exists("message", $aRepodata)) { - if (is_array($aBranches) && count($aBranches)) { - $sRepoCheck = '<span class="ok">' . sprintf(t('class-project-info-repoaccess'), count($aBranches)) . '</span>'; - } else { - $sRepoError=sprintf(t('class-project-error-no-repoaccess'), $aRepodata["error"]); - $sRepoCheck = '<span class="error">' . $sRepoError . '</span>'; - $sMessages.=$this->_oHtml->getBox("error", $sRepoError); - } - - // generate datalist with exisating ssh keys for auth field - $sAuthListitems = ''; - foreach ($this->_getSshKeys() as $sKey) { - $sAuthListitems.='<option value="' . $sKey . '">'; - } - $aForms = array( - 'setup' => array( - 'meta' => array( - 'method' => 'POST', - 'action' => '?', - ), - 'validate' => array(), - 'form' => array( - 'input' . $i++ => array( - 'type' => 'hidden', - 'name' => 'setupaction', - 'value' => 'save', - ), - 'input' . $i++ => array( - 'type' => 'hidden', - 'name' => 'id', - 'value' => $this->_aConfig["id"], - ), - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => '<div class="tabbable"> - <ul class="nav nav-tabs"> - <li class="active"><a href="#tab1" data-toggle="tab">' . $this->_oHtml->getIcon('list').t('setup-metadata') . '</a></li> - <li><a href="#tab2" data-toggle="tab">' . $this->_oHtml->getIcon('repository').t('repositoryinfos') . '</a></li> - - <li><a href="#tab3" data-toggle="tab">' . $this->_oHtml->getIcon('deploy-configfile').t('deploy-configfile') . '</a></li> - <li><a href="#tab4" data-toggle="tab">' . $this->_oHtml->getIcon('deploy-rollout-plugin').t('deploy-rollout-plugin') . '</a></li> - <li><a href="#tab5" data-toggle="tab">' . $this->_oHtml->getIcon('phase').t('phases') . '</a></li> - <li><a href="#tab6" data-toggle="tab">' . $this->_oHtml->getIcon('raw-data').t('raw-data') . '</a></li> - </ul> - <div class="tab-content"> - <div class="tab-pane active" id="tab1"> - - ', - ), - - // -------------------------------------------------- - // Tab for metadata - // -------------------------------------------------- - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'label', - 'label' => t('projectname'), - 'value' => $this->_aPrjConfig["label"], - 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => 'Projekt', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'description', - 'label' => t('projectdescription'), - 'value' => $this->_aPrjConfig["description"], - 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'contact', - 'label' => t('contact'), - 'value' => $this->_aPrjConfig["contact"], - 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - ), - - 'input' . $i++ => $aSelectProjectGroup, - - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => '<p>' . t('messenger') . '</p>', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'messenger[email]', - 'label' => t("messenger-email"), - 'value' => $this->_aPrjConfig["messenger"]["email"], - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - 'autocomplete' => 'off', - ), - - 'input' . $i++ => $aSelectSlack, - - // -------------------------------------------------- - // Tab soources repository & build - // -------------------------------------------------- - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => ' </div><div class="tab-pane" id="tab2"> - <p>' . t('setup-hint-build') . '</p>', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'build[type]', - 'label' => t("build-type"), - 'value' => $this->_aPrjConfig["build"]["type"], - 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'build[url]', - 'label' => t("repository-url"), - 'value' => $this->_aPrjConfig["build"]["url"], - // 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'build[auth]', - 'label' => t("repository-auth"), - 'value' => $this->_aPrjConfig["build"]["auth"], - // 'required' => 'required', - 'list' => 'listauth', // listauth is the next form id below - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - ), - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => '<datalist id="listauth">' . $sAuthListitems . '</datalist>', - ), - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => '<div class="form-group">' - . '<label class="col-sm-2"> </label><div class="col-sm-10">' - . $sRepoCheck - . '</div></div>', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'build[webaccess]', - 'label' => t("repository-urlwebgui"), - 'value' => $this->_aPrjConfig["build"]["webaccess"], - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - ), - 'input' . $i++ => $aPrefixItem, - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => '<div style="clear: both"></div>', - ), - // task#1498 - handle project without "public" directory - 'input' . $i++ => array( - 'type' => 'checkbox', - 'name' => 'build[haspublic]', - 'label' => t("repository-has-public-dir"), - 'required' => false, - 'validate' => 'isastring', - 'options' => array( - '1' => array( - 'label' => t("yes"), - 'checked' => (array_key_exists('haspublic', $this->_aPrjConfig["build"]) ? $this->_aPrjConfig["build"]["haspublic"] : 0), - ), - ), - ), - - // -------------------------------------------------- - // Tab for config and API key - // -------------------------------------------------- - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => ' </div><div class="tab-pane" id="tab3"> - <p>' . t('deploy-configfile-hint') . '</p>', - ), - 'textarea' . $i++ => array( - 'type' => 'textarea', - 'name' => 'deploy[configfile]', - 'label' => t("deploy-configfile"), - 'value' => $this->_aPrjConfig['deploy']["configfile"], - // 'required' => 'required', - 'validate' => 'isastring', - 'cols' => 100, - 'rows' => 10, - 'placeholder' => 'export myvariable="hello world"', - ), - - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'api[secret]', - 'label' => t("api-secret"), - 'value' => $this->_aPrjConfig["api"]["secret"], - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => '', - ), - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => '<div class="col-sm-12">' - . '<p>' . t('api-secret-hint') . '<br>' - . '<a href="#" class="btn btn-default" onclick="$(\'#input'.($i-2).'\').val(generateSecret(64)); return false">'.t("api-secret-generate").'</a>' - . '</p></div>', - ), - - // -------------------------------------------------- - // Tab rollout plugin - // -------------------------------------------------- - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => ' </div><div class="tab-pane" id="tab4"> - <p>' . t('deploy-rollout-plugin-hint') . '</p>', - ), - // select box for active rollout plugin - $aRollout['project-select'], - - // project based config - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => '' - . '<hr>' - .'<label class="col-sm-2">'.t('deploy-rollout-plugin-config') .'</label>' - .'<div class="col-sm-10">'. $aRollout['project-config'].'</div>' - ), - // -------------------------------------------------- - 'input' . $i++ => array( - 'type' => 'markup', - 'value' => ' </div><div class="tab-pane" id="tab5"> - <p>' . sprintf(t("class-project-info-setup-phaseinfos"), $this->getNextPhase()) . '</p>', - ), - ), - ), - ); - // -------------------------------------------------- - // Tab for phases - // -------------------------------------------------- - if ($aSelectForemanGroups) { - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '<strong>'.t("defaults-all-phases").'</strong><br><br>', - ); - $aForms["setup"]["form"]['input' . $i++] = $aSelectForemanGroups; - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '<br><br>', - ); - } - foreach (array_keys($this->getPhases()) as $sPhase) { - - $bActivePhase = $this->isActivePhase($sPhase); - $sUrl = array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["url"] : ""; - $sDeploymethod = array_key_exists("deploymethod", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploymethod"] : ""; - $sDeployhosts = array_key_exists("hosts", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["hosts"] : ""; - - /* - * task-1847 - reove adding ssh key - if($sDeployhosts){ - echo "$sDeployhosts<br>"; - if(!strpos($sDeployhosts, ",")){ - $sCmd=sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sDeployhosts, $sDeployhosts); - exec($sCmd . " 2>&1", $aOut); - echo "<pre>\$ $sCmd<br>" - . implode('<br>', $aOut) - ."</pre>" - ; - } - } - */ - $sDeploytimes = array_key_exists("deploytimes", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploytimes"] : ""; - $sDivId4PhaseSettings = 'divSettings' . $sPhase; - $sDivId4TargetHosts = 'divSettings' . $sPhase . 'hosts'; - - if ($aSelectForemanGroups) { - $iForemanHostgroup = (int) $this->_aPrjConfig['phases'][$sPhase]['foreman-hostgroup']; - $aSelectForemanHostGroup = array( - 'type' => 'select', - 'name' => 'phases[' . $sPhase . '][foreman-hostgroup]', - 'label' => $this->_oHtml->getIcon('foreman') . t("foreman-hostgroup"), - 'options' => array( - OPTION_DEFAULT => array( - 'label' => t('default') . ' (' . $sForemanHostgroupDefault . ')', - 'selected' => $iForemanHostgroup === OPTION_DEFAULT ? 'selected' : false, - ), - OPTION_NONE => array( - 'label' => t('none'), - 'selected' => $iForemanHostgroup === OPTION_NONE ? 'selected' : false, - ), - '' => array( - 'label' => '- - - - - - - - - - - - - - - - - - - - ', - ), - ), - ); - if (is_array($aForemanHostgroups) && count($aForemanHostgroups)) { - foreach ($aForemanHostgroups as $aItem) { - $aSelectForemanHostGroup['options'][$aItem['id']] = array( - 'label' => $aItem['title'], - 'selected' => ($iForemanHostgroup === $aItem['id']) ? 'selected' : false, - ); - } - } - } - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '' - // .'<pre>'.print_r($this->_aPrjConfig["phases"][$sPhase], 1).'</pre>' - /* - . '<a class="'.$sPhase.'">' - . t("phase") . ' ' . $sPhase - . '</a>' - */ - . '<table class="table">' - . '<tbody>' - . '<tr><th class="' . $sPhase . '">' . $this->_oHtml->getIcon('phase') . t("phase") . ' ' . $sPhase . '</th></tr>' - . '<tr><td class="' . ($bActivePhase ? $sPhase : '') . '">' - . '' - ); - - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'checkbox', - 'name' => 'phases[' . $sPhase . '][active]', - 'label' => t("phase-is-active"), - // 'value' => $bUsePuppet, - 'required' => false, - 'validate' => 'isastring', - // 'size' => 100, - // 'placeholder' => '...', - 'options' => array( - '1' => array( - 'label' => t("yes"), - 'checked' => $bActivePhase, - 'onclick' => '$(\'#' . $sDivId4PhaseSettings . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )', - ), - ), - ); - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '' - . '<div id="' . $sDivId4PhaseSettings . '" ' . ($bActivePhase ? '' : ' style="display: none;"') . '">' - ); - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'text', - 'name' => 'phases[' . $sPhase . '][url]', - 'label' => $this->_oHtml->getIcon('url') . t("url-project-website"), - 'value' => $sUrl, - // 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => 'https://' . $sPhase . '.[' . t("project") . '].[...]/', - ); - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'radio', - 'name' => 'phases[' . $sPhase . '][deploymethod]', - 'label' => $this->_oHtml->getIcon('method') . t("deploymethod"), - // 'value' => $bUsePuppet, - // 'required' => 'required', - 'validate' => 'isastring', - // 'size' => 100, - // 'placeholder' => '...', - 'options' => array( - 'none' => array( - 'label' => t("deploymethod-none"), - 'checked' => $sDeploymethod === "none", - 'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'none\' : \'block\') )', - ), - 'rolloutplugin' => array( - // 'label' => t("deploymethod-puppet").' - '. $this->oRolloutPlugin->getName(), - 'label' => t("deploymethod-rolloutplugin"), - 'checked' => $sDeploymethod === "rolloutplugin", - 'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )', - ), - /* - * see deploy method to handle an action - 'sshproxy' => array( - 'label' => t("deploymethod-sshproxy"), - 'checked' => $sDeploymethod==="sshproxy", - 'onclick' => '$(\'#'.$sDivId4TargetHosts.'\').css(\'display\', (this.checked ? \'block\' : \'none\') )', - ), - */ - ), - ); - - - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '' - . '<div id="' . $sDivId4TargetHosts . '" ' . ($sDeploymethod !== "none" ? '' : ' style="display: none;"') . '">' - ); - - // rollout plugin: phase specific overrides - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '' - // . '<hr>' - .'<label class="col-sm-2">'.t('deploy-rollout-plugin-config') .'</label>' - .'<div class="col-sm-10">'.$aRollout[$sPhase].'</div>' - ); - - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'text', - 'name' => 'phases[' . $sPhase . '][hosts]', - 'label' => $this->_oHtml->getIcon('host') . t("phase-targethosts"), - 'value' => $sDeployhosts, - // 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => 'FQDN1,FQDN2', - ); - - /* - if ($sPuppethost) { - - // add ssh host key - $sOut0 = shell_exec(sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sPuppethost, $sPuppethost)); - - $sCmd2 = 'ssh ' . $this->_aConfig["installPackages"]["user"] - . '@' . $sPuppethost - . ' ' . $this->_aConfig["installPackages"]["testcommand"]; - $sOut = 'skip'; - // $sOut = shell_exec($sCmd2); - // Check auf Versionsnummer - mehr als n Zeichen ist mutmasslich eine Fehlermeldung - if (strlen($sOut) > 7) { - $sMessages.=$this->getBox("error", sprintf(t("class-project-error-setup-sudo-pupet-agent-failed"), $sPhase, $sCmd, $sOut)); - $sOut = '<span class="error" title="' . $sCmd . '">' . $sOut . '</span>'; - } else { - $sOut = '<span class="ok">' . sprintf(t("class-project-info-setup-ssh-and-puppet-ok"), $sPuppethost) . '</span>'; - } - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '<div class="form-group">' - . '<label class="col-sm-2"> </label><div class="col-sm-10">' - . $sOut - . '</div></div>', - ); - } - */ - - // when to deploy - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'text', - 'name' => 'phases[' . $sPhase . '][deploytimes]', - 'label' => $this->_oHtml->getIcon('time') . t("deploytimes"), - 'value' => $sDeploytimes, - // 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'placeholder' => isset($this->_aConfig["phases"][$sPhase]["deploytimes"]) ? implode(", ", $this->_aConfig["phases"][$sPhase]["deploytimes"]) : '', - ); - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '' - . '</div>' - ); - - if ($aSelectForemanGroups) { - $aForms["setup"]["form"]['input' . $i++] = $aSelectForemanHostGroup; - } - - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '' - . '</div>' - ); // close div for active phase - - - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '</td></tr></tbody></table>', - ); - } // END: loop over phases - - // -------------------------------------------------- - // Tab for raw data - // -------------------------------------------------- - - $sRolloutDebug='<hr>DEBUG:<br>'; - foreach (array_keys($this->getPhases()) as $sPhase) { - if ($this->isActivePhase($sPhase)){ - $sRolloutDebug.='<strong>'.$sPhase.'</strong>' - . '<pre>Config = '.print_r($this->oRolloutPlugin->getConfig($sPhase), 1).'</pre>' - . '<pre>Commands = '.print_r($this->oRolloutPlugin->getDeployCommands($sPhase), 1).'</pre>' - ; - } - } - - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'markup', - 'value' => '</div>' - - . '<div class="tab-pane" id="tab6">' - . '<br><pre>'.print_r($this->_aPrjConfig, 1).'</pre>' - . $sRolloutDebug - . '</div>' - - . '</div>' - . '</div>' - . '<div style="clear: both; margin-bottom: 1em;"></div>' - - - . '<hr>', - ); - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'submit', - 'name' => 'btnsave', - 'label' => t("save"), - 'value' => $this->_oHtml->getIcon('sign-ok').t("save"), - ); - - $oForm = new formgen($aForms); - return $sMessages . $oForm->renderHtml("setup"); - } - - /** - * return html code for the setup form for a new project - * @return string - */ - public function renderNewProject() { - global $aParams; - if (!$this->oUser->hasPermission("project-action-create")) { - return $this->oUser->showDenied(); - } - - require_once ("formgen.class.php"); - $i = 0; - $sID = array_key_exists("id", $aParams) ? $aParams["id"] : ""; - - $aForms = array( - 'setup' => array( - 'meta' => array( - 'method' => 'POST', - 'action' => '?', - ), - 'validate' => array(), - 'form' => array( - 'input' . $i++ => array( - 'type' => 'hidden', - 'name' => 'setupaction', - 'value' => 'create', - ), - 'input' . $i++ => array( - 'type' => 'text', - 'name' => 'id', - 'label' => t("class-project-info-setup-projectId"), - 'value' => $sID, - 'required' => 'required', - 'validate' => 'isastring', - 'size' => 100, - 'pattern' => '[a-z0-9\-_]*', - 'placeholder' => t("class-project-info-setup-projectId-placeholder"), - ), - ), - ), - ); - $aForms["setup"]["form"]['input' . $i++] = array( - 'type' => 'submit', - 'name' => 'btnsave', - 'label' => t("save"), - 'value' => $this->_oHtml->getIcon('sign-ok') . t("save"), - ); - - $oForm = new formgen($aForms); - return $oForm->renderHtml("setup"); - } } diff --git a/public_html/deployment/classes/project_gui.class.php b/public_html/deployment/classes/project_gui.class.php new file mode 100644 index 00000000..ca923ad1 --- /dev/null +++ b/public_html/deployment/classes/project_gui.class.php @@ -0,0 +1,1713 @@ +<?php + +echo 'DEBUG: GUI class was loaded - '.__FILE__.'<br>'; +require_once 'project.class.php'; +require_once 'htmlguielements.class.php'; + + +/* ###################################################################### + + IML DEPLOYMENT + + class project for all actions for single project + Rendering of web ui + + --------------------------------------------------------------------- + 2013-11-08 Axel <axel.hahn@iml.unibe.ch> + ###################################################################### */ + +/** + * class for single project + */ +// class project { +class projectgui extends project { + + // ---------------------------------------------------------------------- + // private functions + // ---------------------------------------------------------------------- + + /** + * return html code for a div with background color based on a checksum of the given text + * @param string $sText text that is used for checksum; if false ist returns a gray + * @param string $sContent optional: text to show + * @return string + */ + private function _getChecksumDiv($sText, $sContent='') { + if ($sText){ + + // color ranges in decimal values for RGB from ... to + $iFgStart=60; $iFgEnd=160; + $iBgStart=200; $iBgEnd=250; + + // deivider: 3 digits of md5 will be extracted + $iFgDivider=16*16*16/($iFgEnd-$iFgStart); + $iBgDivider=16*16*16/($iBgEnd-$iBgStart); + + $sHash=md5($sText); + $sColor='' + . 'color: rgba(' + . ($iFgStart + round(hexdec(substr($sHash,0,3))/$iFgDivider)) . ',' + . ($iFgStart + round(hexdec(substr($sHash,3,3))/$iFgDivider)) . ',' + . ($iFgStart + round(hexdec(substr($sHash,6,3))/$iFgDivider)) . ',' + . '1' + . ');' + . 'background: rgba(' + . ($iBgStart + round(hexdec(substr($sHash,0,3))/$iBgDivider)) . ',' + . ($iBgStart + round(hexdec(substr($sHash,3,3))/$iBgDivider)) . ',' + . ($iBgStart + round(hexdec(substr($sHash,6,3))/$iBgDivider)) . ',' + . '1' + . ');' + ; + } else { + $sColor = "color: #888; background: #ccc;"; + } + return '<div style="' . $sColor . '; border-top: 3px solid; ">'.($sContent ? $sContent : ' ').'</div>'; + } + + + /** + * get html code for the colored bar on top of each phase detail items + * @param string $sPhase phase of a project + * @param string $sPlace place in the given phase + * @return string + */ + private function _renderBar($sPhase, $sPlace) { + $aDataPhase = $this->getPhaseInfos($sPhase); + $aData = $aDataPhase[$sPlace]; + if (!array_key_exists("revision", $aData)) { + return false; + } + return $this->_getChecksumDiv($aData["revision"]); + } + + private function _renderHostsData($aData) { + $sReturn = ''; + if (array_key_exists('_hosts', $aData)) { + + // $sReturn.= print_r($aData['_hosts'], 1); + $sReturn.= '<div class="hosts">' + . '<br><strong>' . t('hosts') . ':</strong><br>' + ; + foreach ($aData['_hosts'] as $sHostname => $aHostinfos) { + $oUpdateDate = date("U", strtotime($aHostinfos['time'])); + $iAgeUpdate = round((date("U") - $oUpdateDate) / 60); + $sAge = $iAgeUpdate < 60 * 60 * 13 ? $iAgeUpdate . " min" : "??"; + + $sReturn.= '<div class="host">' + . $this->_getChecksumDiv( + $aHostinfos['_data']['revision'], + $this->_oHtml->getIcon('host').'<br>' . $sHostname + ) + . "($sAge)" + . '</div>' + ; + } + $sReturn.= '</div><div style="clear: both;"></div>'; + } + return $sReturn; + } + + /** + * get html code for list of hosts in a phase + * @param string $sPhase phase of a project + * @return string + */ + private function _renderHosts($sPhase) { + $aDataPhase = $this->getPhaseInfos($sPhase); + if (is_array($aDataPhase) && array_key_exists('deployed', $aDataPhase)) { + return $this->_renderHostsData($aDataPhase['deployed']); + } + return ''; + } + + /** + * get html code for list of files in a phase + * @param string $sPhase phase of a project + * @return string + */ + private function _renderFiles($sPhase) { + $sReturn = ''; + $aFiles = $this->getBuildfilesByPlace($sPhase, 'ready2install'); + if (!$aFiles || !$aFiles['filecount']) { + return ''; + } + $sReturn.='<strong>' . t("filelist") . '</strong> (' . $aFiles['filecount'] . '):<br>'; + foreach ($aFiles['files'] as $sFilename => $aData) { + $sReturn.='<div class="file file-' . $aData['type'] . ' fileext-' . $aData['extension'] . '" title="' . $sFilename . ' (' . $aData['type'] . ')">' + . $aData['icon'] . $sFilename + // . ' ('.$aData['type'].')' + . '</div>' + ; + } + $sReturn.='(' . $aFiles['totalsize-hr'] . ')'; + return $sReturn; + } + + // ---------------------------------------------------------------------- + // RENDERING + // ---------------------------------------------------------------------- + + + /** + * render html for a row with td for all places of a phase + * @param string $sPhase phase + * @param bool $bActions draw action links (deploy, accept) on/ off + * @param bool $bLong use long variant to display infos? + * @return string|boolean + */ + public function renderAllPhaseDetails($sPhase, $bActions = true, $bLong = true) { + if (!$sPhase) { + return false; + } + if (!$this->isActivePhase($sPhase)) { + return ' + <td class="td-phase-' . $sPhase . ' td-phase-inactive ' . $this->_aConfig["id"] . '" colspan="' . count($this->_aPlaces) . '"> + <div class="versioninfo center inactive">' . $this->_oHtml->getIcon('sign-info').t('inactive') . '</div> + </td>'; + } + $sRow2 = false; + + $aRows = array(); + $sLastPlace = ''; + + foreach (array_keys($this->_aPlaces) as $sPlace) { + $aRows[$sPlace] = $this->renderPhaseDetail($sPhase, $sPlace, $bActions, $bLong); + + // generate ">>" sign for lastly generated td + if ($sLastPlace && array_key_exists("version", $this->_aData["phases"][$sPhase][$sLastPlace]) + && array_key_exists("version", $this->_aData["phases"][$sPhase][$sPlace]) + && $this->_aData["phases"][$sPhase][$sLastPlace]["version"] == $this->_aData["phases"][$sPhase][$sPlace]["version"] + && !$bLong + ) { + $aRows[$sLastPlace] = $this->_renderBar($sPhase, $sPlace) . "»"; + } + $sLastPlace = $sPlace; + } + + foreach (array_keys($this->_aPlaces) as $sPlace) { + $sRow2.='<td class=" td-phase-'.$sPhase.' td-place-'.$sPlace.' td' . $this->_aConfig["id"] . '">' . $aRows[$sPlace] . '</td>'; + } + return $sRow2; + } + + /** + * return html code for current project errors by rendering a box per error in $this->_errors + * @return string + */ + public function renderErrorBoxes(){ + $sReturn=''; + if(count($this->_errors)){ + foreach($this->_errors as $sError){ + $sReturn.=$this->_oHtml->getBox("error", $sError); + } + } + return $sReturn; + } + + + /** + * render html code for info link that shows popup with metadata on mouseover + * @param array $aInfos metainfos of the package (from json file) + * @param array $aOptions options + * title - tile in popover; default: empty + * label - link label; default: empty (results in Infos|ERROR) + * more - additional infos in popover; default: empty + * hpos - horizontal position; one of left|right; default: right + * @return string + */ + public function renderInfoLink($aInfos, $aOptions = array()) { + $sReturn = ''; + $bIsError = false; + $this->_oHtml = new htmlguielements(); + + $sInfos=''; + $sTitle=''; + if (array_key_exists("title", $aOptions) && $aOptions["title"]) { + $sTitle.=$aOptions["title"]; + } + if (array_key_exists("ok", $aInfos)) { + $sLinktitle = t('infos'); + if (array_key_exists("message", $aInfos)) { + $sInfos.=$this->_getChecksumDiv($aInfos["revision"], + $this->_oHtml->getIconByType('calendar') . t('build-from') . ' ' . date("d.m.Y H:i:s", strtotime($aInfos["date"])) . '<br>' + . $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aInfos["branch"] . '<br>' + . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aInfos["revision"]) . '<br>' + . $this->_oHtml->getIconByType('comment') . t('commitmessage') . ': ' + ) + . '<pre>' . strip_tags($aInfos["message"], '<br>') . '</pre>'; + if (array_key_exists("more", $aOptions)) { + $sInfos.=$aOptions["more"]; + } + } + } else { + $bIsError = true; + if (!$sTitle) { + $sTitle.=' ' . t('error'); + } + $sLinktitle = t('error'); + $sInfos = $aInfos["error"]; + } + $sInfos.=$this->_renderHostsData($aInfos); + + if (array_key_exists("label", $aOptions) && $aOptions["label"]) { + $sLinktitle.=$aOptions["label"]; + } + + // render html + $sId = 'info' . md5($sInfos); + $sReturn = '<a href="#" class="btn ' . ($bIsError ? 'btn-danger' : 'btn-default') . '" title="" onclick="showIdAsModalMessage(\'' . $sId . '\'); return false;">' + // . '<i class="fa fa-info"></i> ' + . $sLinktitle + . '</a><div id="' . $sId . '" style="display: none;" '; + if (array_key_exists("hpos", $aOptions)) { + $sReturn.=' class="' . $aOptions["hpos"] . '"'; + } + $sReturn.='>'; + + if ($sTitle) { + $sReturn.='<span class="title">' . $sTitle . '</span><br><br>'; + } + + $sReturn.=$sInfos . '</div>'; + + if ($bIsError) { + // $sReturn = '<div class="error">' . $sReturn . '</div>'; + } + + return $sReturn; + } + + /** + * render html for a colored link to any project action + * @param string $sFunction name of the action; one of accept|build|cleanup|deploy|new|overview|phase|rollback|setup + * @param string $sPhase current phase where to place the link + * @return string + */ + public function renderLink($sFunction, $sPhase = false, $sVersion = false) { + $sFirst = $this->getNextPhase(); + $sNext = $this->getNextPhase($sPhase); + $aLinkdata = array( + 'default' => array('class' => ''), + 'accept' => array('class' => $sNext, + 'hint' => sprintf(t("accept-hint"), $sPhase, $sNext), + 'label' => t('accept'), + ), + 'build' => array('class' => $sFirst, + 'hint' => sprintf(t("build-hint"), $sFirst), + 'label' => t('build'), + 'role' => 'buildProject' + ), + 'cleanup' => array('class' => ''), + 'deploy' => array('class' => $sPhase, + 'hint' => sprintf(t("deploy-hint"), $sPhase), + 'label' => t('deploy'), + ), + 'new' => array( + 'hint' => t("new-project-hint"), + 'label' => t('new-project'), + ), + 'overview' => array('class' => '', + 'hint' => t('menu-project-home') . ' [' . $this->getLabel() . ']', + 'label' => $this->getLabel() + ), + 'phase' => array('icon' => $this->_oHtml->getIcon('phase'), 'class' => $sPhase, + 'hint' => sprintf(t('phase-details-hint'), $sPhase), + 'label' => t('phase-details') + ), + 'rollback' => array('class' => $sPhase, + 'hint' => sprintf(t('rollback-hint'), $sPhase, $sVersion), + 'label' => t('rollback') + ), + 'setup' => array('class' => $sPhase, + 'hint' => sprintf(t('setup-hint'), $sPhase, $sVersion), + 'label' => t('setup') + ), + ); + /* + if (!$this->oUser->hasRole("project-action-$sFunction")){ + // $sClass .= ' disabled'; + // return '<span title="no permission [project-action-'.$sFunction.']">[ ]</span>'; + } + * + */ + // fuer wen ist der Link + $sRole = ''; + $sOnMouseover = ''; + $sOnMouseout = ''; + switch($sFunction){ + case 'accept'; + $sRole = 'developer'; + if ($sNext == "live") { + $sRole = 'pl'; + // $aLinkdata[$sFunction]['icon']='glyphicon glyphicon-star'; + } + $sOnMouseover = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'; + $sOnMouseout = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');'; + break; + case 'build'; + $sRole = 'developer'; + $sOnMouseover = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'; + $sOnMouseout = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');'; + break; + case 'deploy'; + $sRole = 'developer'; + $sOnMouseover = '$(\'.td-phase-' . $sPhase . '.td-place-ready2install.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');' + .'$(\'.td-phase-' . $sPhase . '.td-place-deployed.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');' + ; + $sOnMouseout = '$(\'.td-phase-' . $sPhase . '.td-place-ready2install.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');' + .'$(\'.td-phase-' . $sPhase . '.td-place-deployed.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');' + ; + break; + } + + // $sClass = $sPhase; + $sIconClass = (array_key_exists($sFunction, $aLinkdata)) ? $aLinkdata[$sFunction]['icon'] : $aLinkdata['default']['icon']; + $sHint = ( + array_key_exists($sFunction, $aLinkdata) && array_key_exists("hint", $aLinkdata[$sFunction]) + ) ? $aLinkdata[$sFunction]['hint'] : ""; + $sLabel = ( + array_key_exists($sFunction, $aLinkdata) && array_key_exists("label", $aLinkdata[$sFunction]) + ) ? $aLinkdata[$sFunction]['label'] : $sFunction; + $sClass = ( + array_key_exists($sFunction, $aLinkdata) && array_key_exists("class", $aLinkdata[$sFunction]) + ) ? $aLinkdata[$sFunction]['class'] : ''; + if ($sRole) { + $sClass .= " role role" . $sRole; + } + + $sLink = "/deployment/" . ($this->_aConfig["id"] ? $this->_aConfig["id"] : 'all/setup') . "/"; + if ($sFunction != "overview") { + $sLink.="$sFunction/"; + } + if ($sPhase) { + $sLink.="$sPhase/"; + } + if ($sVersion) { + $sLink.="$sVersion/"; + } + if (!$this->oUser->hasPermission("project-action-$sFunction")) { + // $sClass .= ' disabled'; + return '<span class="btn disabled btn-default" title="no permission [project-action-' . $sFunction . '] for user [' . $this->oUser->getUsername() . ']"><i class="' . $sIconClass . '"></i> ' . $sLabel . '</span>'; + } + + return $this->_oHtml->getLinkButton(array( + 'href' => $sLink, + 'title' => $sHint, + 'class' => 'btn btn-default ' . $sClass, + 'type' => $sFunction, + 'onmouseover' => $sOnMouseover, + 'onmouseout' => $sOnMouseout, + 'label' => $sLabel, + )); + // return '<a href="' . $sLink . '" ' . $sOnMouseover . ' title="' . $sHint . '" class="btn btn-default ' . $sClass . '"><i class="' . $sIconClass . '"></i> ' . $sLabel . '</a>'; + } + + /** + * return html code for the setup form for a new project + * @return string + */ + public function renderNewProject() { + global $aParams; + if (!$this->oUser->hasPermission("project-action-create")) { + return $this->oUser->showDenied(); + } + + require_once ("formgen.class.php"); + $i = 0; + $sID = array_key_exists("id", $aParams) ? $aParams["id"] : ""; + + $aForms = array( + 'setup' => array( + 'meta' => array( + 'method' => 'POST', + 'action' => '?', + ), + 'validate' => array(), + 'form' => array( + 'input' . $i++ => array( + 'type' => 'hidden', + 'name' => 'setupaction', + 'value' => 'create', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'id', + 'label' => t("class-project-info-setup-projectId"), + 'value' => $sID, + 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'pattern' => '[a-z0-9\-_]*', + 'placeholder' => t("class-project-info-setup-projectId-placeholder"), + ), + ), + ), + ); + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'submit', + 'name' => 'btnsave', + 'label' => t("save"), + 'value' => $this->_oHtml->getIcon('sign-ok') . t("save"), + ); + + $oForm = new formgen($aForms); + return $oForm->renderHtml("setup"); + } + /** + * render html for a place of a phase + * @param string $sPhase phase + * @param string $sPlace name of the place; one of onhold|ready2install|deployed + * @param bool $bActions draw action links (deploy, accept) on/ off + * @param bool $bLong use long variant to display infos? + * @return string|boolean + */ + public function renderPhaseDetail($sPhase, $sPlace, $bActions = true, $bLong = true) { + + if (!$sPhase) { + return false; + } + if (!$sPlace) { + return false; + } + if (!$this->isActivePhase($sPhase)) { + return false; + } + if (!array_key_exists($sPlace, $this->_aPlaces)) { + return false; + } + + $sReturn = false; + $aDataPhase = $this->getPhaseInfos($sPhase); + $aData = $aDataPhase[$sPlace]; + // foreach($aDataPhase[$sPlace] as $aData) { + if (array_key_exists("ok", $aData) && array_key_exists("version", $aData)) { + // TODO: getChecksumDiv anhand der Repo-Versionsnummer - dann kann man beim build auch die Farbe mit dem Repo HEAD vergleichen + // time + $sDateFormat = "d.m.Y H:i"; + $oPkgDate = date("U", strtotime($aData["date"])); + /* + $iAge=date("U")-$oPkgDate; + $sAgeClass=""; + if ($iAge< 60*60*24*3){ + $sAgeClass="last1d"; + } + if ($iAge< 60*60){ + $sAgeClass="last1h"; + } + */ + + if ($bLong) { + // long display of the revision + // $sJsonUrl = $this->_getInfofile($sPhase, $sPlace); + $sReturn .=$this->_getChecksumDiv( + $aData["revision"], + $this->_oHtml->getIconByType('calendar') .' ' . date($sDateFormat, $oPkgDate) + . $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aData["branch"] . '<br>' + . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aData["revision"]) . '<br>' + . $this->_oHtml->getIconByType('comment') . t('commitmessage') . ':<br>' + ) + . '<pre>' . strip_tags($aData["message"], '<br>') . '</pre>' + // . '<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sJsonUrl . '">' . $sJsonUrl . '</a><br>' + ; + if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) { + $sUrl = $this->_aPrjConfig["phases"][$sPhase]["url"]; + $sReturn.=$this->_oHtml->getIconByType('link-extern') . ' '. t('url') . ': <a href="' . $sUrl . '">' . $sUrl . '</a><br>'; + } + } else { + $sReturn .= $this->_getChecksumDiv( + $aData["revision"], + $this->_oHtml->getIconByType('calendar') .' ' . date($sDateFormat, $oPkgDate) + ); + if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) { + $sMore = $this->_oHtml->getIconByType('link-extern').' ' + . t('url') + . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>'; + } + + $sReturn.=' ' . $this->renderInfoLink( + $aData, array( + 'title' => $this->getLabel() . " :: $sPhase :: $sPlace", + 'more' => $sMore, + ) + ); + } + + switch ($sPlace) { + case "onhold": + if (array_key_exists("phases", $this->_aConfig) && array_key_exists($sPhase, $this->_aConfig["phases"])) { + // $sReturn .= print_r($this->_aConfig["phases"][$sPhase], true); + if (count($this->_getDeploytimes($sPhase))) { + $sReturn .= '<br>'.$this->_oHtml->getIcon('time').t('deploytimes') . ':<br>' + . implode("<br>", array_values($this->_getDeploytimes($sPhase))) + . '<br>'; + } + if ($bActions) { + $sReturn .= ' ' . $this->renderLink("deploy", $sPhase); + } + } + break; + + case "ready2install": + break; + + case "deployed": + if ($bActions && $this->canAcceptPhase($sPhase)) { + $sReturn .= ' ' . $this->renderLink("accept", $sPhase); + } + break; + default: + break; + } + // $this->_getChecksumDiv($aData["revision"]) + } else { + if (array_key_exists("error", $aData)) { + $sReturn.='' + . $this->renderInfoLink(array('error' => $aData["error"]), array()) + ; + } else if (array_key_exists("warning", $aData)) { + $sReturn.= '<div class="warning">'.$this->_oHtml->getIcon('sign-info'). t('warning') . ':<br>' . $aData["warning"] . '</div>'; + } else { + return false; + // $sReturn.= t('empty'); + } + } // if + // } // for + return $sReturn; + } + + /** + * render html for the project overview; it shows the defined phases for + * the project as a table + * @return type + */ + public function renderPhaseInfo() { + $sRow1 = false; + $sRow2 = false; + foreach ($this->getActivePhases() as $sPhase) { + $sRow1.='<th class="' . $sPhase . '">' . $sPhase . '</th>'; + $sRow2.='<td class="' . $sPhase . '">' + . t('url') . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>' + . '<br>' . t('deploytimes') . ':<br>'; + if (count($this->_getDeploytimes($sPhase))) { + $sRow2.=implode("<br>", $this->_getDeploytimes($sPhase)); + } else { + $sRow2.=t('deploytimes-immediately'); + } + $sRow2.='<br>' . $this->renderLink("phase", $sPhase) + . $this->_renderHosts($sPhase) + . '<br>' + . $this->_renderFiles($sPhase) + . '</td>'; + } + return '<table><thead><tr>' . $sRow1 . '</tr></thead><tbody><tr>' . $sRow2 . '</tr></tbody></table>'; + } + + /** + * render html for a row with td for all places (first row) + * @param string $sPhase phase (just needed for coloring) + * @return string + */ + public function renderPlacesAsTd($sPhase) { + $sRow1 = ''; + foreach (array_keys($this->_aPlaces) as $sPlace) { + $sRow1.='<td class="' . $sPhase . ' ' . $this->_aConfig["id"] . ' tdphase">' . t($sPlace) . '</td>'; + } + return $sRow1; + } + + /** + * return html code for the setup form of an exsiting project + * @return string + */ + public function renderProjectSetup() { + if (!$this->oUser->hasPermission("project-action-setup")) { + return $this->oUser->showDenied(); + } + $sMessages = ''; + require_once ("formgen.class.php"); + + + $aSelectProjectGroup = array( + 'type' => 'select', + 'name' => 'projectgroup', + 'label' => t("projectgroup"), + 'options' => array( + OPTION_NONE => array( + 'label' => t('none'), + ), + '' => array( + 'label' => '- - - - - - - - - - - - - - - - - - - - ', + ), + ), + ); + foreach($this->_aConfig['projectgroups'] as $sGroupid=>$sGroupLabel){ + $bActive=$this->getProjectGroup() === $sGroupid; + $aSelectProjectGroup['options'][$sGroupid] = array( + 'label' => $sGroupLabel, + 'selected' => $bActive ? 'selected' : false, + ); + } + + $aSelectSlack = array( + 'type' => 'hidden', + 'name' => 'messenger[slack]', + 'value' => false, + ); + if ( + isset($this->_aConfig['messenger']['slack']['presets']) + && count($this->_aConfig['messenger']['slack']['presets']) + ) { + $aSelectSlack = array( + 'type' => 'select', + 'name' => 'messenger[slack]', + 'label' => t("messenger-slack"), + 'options' => array( + OPTION_NONE => array( + 'label' => t('none'), + ), + '' => array( + 'label' => '- - - - - - - - - - - - - - - - - - - - ', + ), + ), + ); + foreach($this->_aConfig['messenger']['slack']['presets'] as $sSlackUrl=>$aSlackCfg){ + $bActive=$this->_aPrjConfig['messenger']['slack'] === $sSlackUrl; + $aSelectSlack['options'][$sSlackUrl] = array( + 'label' => array_key_exists('label', $aSlackCfg) ? $aSlackCfg['label'] : $sSlackUrl, + 'selected' => $bActive ? 'selected' : false, + ); + } + + } + // ---------- Build plugins + /* + + $aPluginsBuild = array( + 'select' => array( + 'type' => 'checkbox', + 'name' => 'build[enabled_build_plugins]', + 'label' => t("build-plugins"), + 'options' => [], + ), + // 'project-config' => '', + ); + foreach (array_keys($this->getConfiguredPlugins('build')) as $sPluginName){ + + $sPluginFile=$this->_getPluginFilename('build', $sPluginName); + $TmpRolloutPlugin = false; + $sMyClassname='build_'. $sPluginName; + if(file_exists($sPluginFile)){ + try{ + include_once $this->_getPluginFilename('build', $sPluginName); + $TmpRolloutPlugin = new $sMyClassname([]); + echo "FOUND $sMyClassname<br>"; + $aPluginsBuild['select']['options'][$sPluginName]=array( + 'label' => $TmpRolloutPlugin->getName(), + 'checked' => $bActive, + // 'onclick' => '$(\'.'.$sMyDivClass.'\').hide(); $(\'.' . $sMyDivClassActive . '\').show();', + ); + } catch (Exception $ex) { + + } + } else { + $aRollout['project-select']['options'][$sPluginName]=array( + 'label' => 'not found: <span class="error">' . $sMyClassname . '</span>', + 'checked' => false, + 'disabled' => "disabled", + ); + + + } + } + echo '<pre>'; print_r($aPluginsBuild); die(__METHOD__); + */ + + // ---------- /Build plugins + + // ---------- Rollout plugins + $aRollout = array( + 'project-select' => array( + 'type' => 'radio', + 'name' => 'deploy[enabled_rollout_plugin]', + 'label' => t("deploy-rollout-plugin"), + ), + 'project-config' => '', + ); + foreach (array_keys($this->getConfiguredPlugins('rollout')) as $sPluginName){ + + $sPluginFile=$this->_getPluginFilename('rollout', $sPluginName); + $TmpRolloutPlugin = false; + $sMyClassname='rollout_'. $sPluginName; + $sMyDivId='rollout-'. $sPluginName.'-config'; + $sMyDivClass='rolloutconfigdiv'; + $sMyDivClassActive='rolloutconfigdiv-'. $sPluginName; + $bActive=$sPluginName === $this->oRolloutPlugin->getId(); + + if(file_exists($sPluginFile)){ + try{ + include_once $this->_getPluginFilename('rollout', $sPluginName); + $TmpRolloutPlugin = new $sMyClassname(array( + 'lang'=>$this->_aConfig['lang'], + 'phase'=>false, + 'globalcfg'=>$this->_aConfig['plugins']['rollout'][$sPluginName], + 'projectcfg'=>$this->_aPrjConfig, + )); + $aRollout['project-select']['options'][$sPluginName]=array( + 'label' => $TmpRolloutPlugin->getName(), + 'checked' => $bActive, + 'onclick' => '$(\'.'.$sMyDivClass.'\').hide(); $(\'.' . $sMyDivClassActive . '\').show();', + ); + + $aRollout['project-config'].='' + . '<div id="'.$sMyDivId.'" class="'.$sMyDivClass.' '.$sMyDivClassActive.'"' + . ($bActive ? '' : 'style="display: none;"' ) + . '>' + . $TmpRolloutPlugin->renderFormdata4Project() + . '</div>' + ; + + // generate form firlds for each phase + foreach(array_keys($this->getPhases()) as $sMyPhase){ + $aRollout[$sMyPhase].='' + . '<div id="'.$sMyDivId.'-'.$sMyPhase.'" class="'.$sMyDivClass.' '.$sMyDivClassActive.'"' + . ($bActive ? '' : 'style="display: none;"' ) + . '>' + . $TmpRolloutPlugin->renderFormdata4Phase($sMyPhase) + . '</div>' + ; + } + } catch (Exception $ex) { + + } + } else { + $aRollout['project-select']['options'][$sPluginName]=array( + 'label' => 'not found: <span class="error">' . $sMyClassname . '</span>', + 'checked' => false, + 'disabled' => "disabled", + ); + + + } + } + // ---------- /Rollout plugins + + $aForemanHostgroups = false; + $iForemanHostgroupDefault = false; + $sForemanHostgroupDefault = false; + if (array_key_exists('foreman', $this->_aConfig)) { + // echo '<pre>' . print_r($this->_aPrjConfig, 1) . '</pre>'; + $iForemanHostgroupDefault = (int) $this->_aPrjConfig['deploy']['foreman']['hostgroup']; + require_once('foremanapi.class.php'); + $oForeman = new ForemanApi($this->_aConfig['foreman']); + // $oForeman->setDebug(1); + // $oForeman->selfcheck(); die(__FUNCTION__); + + $aForemanHostgroups = $oForeman->read(array( + 'request' => array( + array('hostgroups'), + // array('operatingsystems',4), + ), + 'response' => array( + 'id', 'title' + ), + )); + $aSelectForemanGroups = array( + 'type' => 'select', + 'name' => 'deploy[foreman][hostgroup]', + 'label' => $this->_oHtml->getIcon('foreman') . t("foreman-hostgroup"), + 'options' => array( + OPTION_NONE => array( + 'label' => t('none'), + ), + '' => array( + 'label' => '- - - - - - - - - - - - - - - - - - - - ', + ), + ), + ); + if ($aForemanHostgroups && count($aForemanHostgroups)) { + foreach ($aForemanHostgroups as $aItem) { + $bActive=$iForemanHostgroupDefault === (int) $aItem['id']; + $aSelectForemanGroups['options'][$aItem['id']] = array( + 'label' => $aItem['title'], + 'selected' => $bActive ? 'selected' : false, + ); + $sForemanHostgroupDefault = $bActive ? $aItem['title'] : $sForemanHostgroupDefault; + } + } + } + + + $i = 0; + + $aPrefixItem = count($this->getVersions()) ? + array( + 'type' => 'markup', + 'value' => '<div class="form-group"> + <label class="col-sm-2">' . t('fileprefix') . '</label> + <div class="col-sm-10"> + <input id="inputprefix" type="hidden" name="fileprefix" value="' . $this->_aPrjConfig["fileprefix"] . '"> + ' . $this->_aPrjConfig["fileprefix"] . ' + </div></div> + ', + ) : array( + 'type' => 'text', + 'name' => 'fileprefix', + // 'disabled' => 'disabled', + 'label' => t('fileprefix-label'), + 'value' => $this->_aPrjConfig["fileprefix"], + 'required' => 'required', + 'validate' => 'isastring', + 'pattern' => '[a-z0-9\-_]*', + 'size' => 100, + 'placeholder' => '', + ); + + // detect access to repo url + $aBranches=$this->getRemoteBranches(); + // $aRepodata = $this->getRepoRevision(); + + // if (is_array($aRepodata) && array_key_exists("message", $aRepodata)) { + if (is_array($aBranches) && count($aBranches)) { + $sRepoCheck = '<span class="ok">' . sprintf(t('class-project-info-repoaccess'), count($aBranches)) . '</span>'; + } else { + $sRepoError=sprintf(t('class-project-error-no-repoaccess'), $aRepodata["error"]); + $sRepoCheck = '<span class="error">' . $sRepoError . '</span>'; + $sMessages.=$this->_oHtml->getBox("error", $sRepoError); + } + + // generate datalist with exisating ssh keys for auth field + $sAuthListitems = ''; + foreach ($this->_getSshKeys() as $sKey) { + $sAuthListitems.='<option value="' . $sKey . '">'; + } + $aForms = array( + 'setup' => array( + 'meta' => array( + 'method' => 'POST', + 'action' => '?', + ), + 'validate' => array(), + 'form' => array( + 'input' . $i++ => array( + 'type' => 'hidden', + 'name' => 'setupaction', + 'value' => 'save', + ), + 'input' . $i++ => array( + 'type' => 'hidden', + 'name' => 'id', + 'value' => $this->_aConfig["id"], + ), + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => '<div class="tabbable"> + <ul class="nav nav-tabs"> + <li class="active"><a href="#tab1" data-toggle="tab">' . $this->_oHtml->getIcon('list').t('setup-metadata') . '</a></li> + <li><a href="#tab2" data-toggle="tab">' . $this->_oHtml->getIcon('repository').t('repositoryinfos') . '</a></li> + + <li><a href="#tab3" data-toggle="tab">' . $this->_oHtml->getIcon('deploy-configfile').t('deploy-configfile') . '</a></li> + <li><a href="#tab4" data-toggle="tab">' . $this->_oHtml->getIcon('deploy-rollout-plugin').t('deploy-rollout-plugin') . '</a></li> + <li><a href="#tab5" data-toggle="tab">' . $this->_oHtml->getIcon('phase').t('phases') . '</a></li> + <li><a href="#tab6" data-toggle="tab">' . $this->_oHtml->getIcon('raw-data').t('raw-data') . '</a></li> + </ul> + <div class="tab-content"> + <div class="tab-pane active" id="tab1"> + + ', + ), + + // -------------------------------------------------- + // Tab for metadata + // -------------------------------------------------- + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'label', + 'label' => t('projectname'), + 'value' => $this->_aPrjConfig["label"], + 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => 'Projekt', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'description', + 'label' => t('projectdescription'), + 'value' => $this->_aPrjConfig["description"], + 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'contact', + 'label' => t('contact'), + 'value' => $this->_aPrjConfig["contact"], + 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + ), + + 'input' . $i++ => $aSelectProjectGroup, + + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => '<p>' . t('messenger') . '</p>', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'messenger[email]', + 'label' => t("messenger-email"), + 'value' => $this->_aPrjConfig["messenger"]["email"], + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + 'autocomplete' => 'off', + ), + + 'input' . $i++ => $aSelectSlack, + + // -------------------------------------------------- + // Tab soources repository & build + // -------------------------------------------------- + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => ' </div><div class="tab-pane" id="tab2"> + <p>' . t('setup-hint-build') . '</p>', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'build[type]', + 'label' => t("build-type"), + 'value' => $this->_aPrjConfig["build"]["type"], + 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'build[url]', + 'label' => t("repository-url"), + 'value' => $this->_aPrjConfig["build"]["url"], + // 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'build[auth]', + 'label' => t("repository-auth"), + 'value' => $this->_aPrjConfig["build"]["auth"], + // 'required' => 'required', + 'list' => 'listauth', // listauth is the next form id below + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + ), + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => '<datalist id="listauth">' . $sAuthListitems . '</datalist>', + ), + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => '<div class="form-group">' + . '<label class="col-sm-2"> </label><div class="col-sm-10">' + . $sRepoCheck + . '</div></div>', + ), + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'build[webaccess]', + 'label' => t("repository-urlwebgui"), + 'value' => $this->_aPrjConfig["build"]["webaccess"], + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + ), + 'input' . $i++ => $aPrefixItem, + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => '<div style="clear: both"></div>', + ), + // task#1498 - handle project without "public" directory + 'input' . $i++ => array( + 'type' => 'checkbox', + 'name' => 'build[haspublic]', + 'label' => t("repository-has-public-dir"), + 'required' => false, + 'validate' => 'isastring', + 'options' => array( + '1' => array( + 'label' => t("yes"), + 'checked' => (array_key_exists('haspublic', $this->_aPrjConfig["build"]) ? $this->_aPrjConfig["build"]["haspublic"] : 0), + ), + ), + ), + + // -------------------------------------------------- + // Tab for config and API key + // -------------------------------------------------- + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => ' </div><div class="tab-pane" id="tab3"> + <p>' . t('deploy-configfile-hint') . '</p>', + ), + 'textarea' . $i++ => array( + 'type' => 'textarea', + 'name' => 'deploy[configfile]', + 'label' => t("deploy-configfile"), + 'value' => $this->_aPrjConfig['deploy']["configfile"], + // 'required' => 'required', + 'validate' => 'isastring', + 'cols' => 100, + 'rows' => 10, + 'placeholder' => 'export myvariable="hello world"', + ), + + 'input' . $i++ => array( + 'type' => 'text', + 'name' => 'api[secret]', + 'label' => t("api-secret"), + 'value' => $this->_aPrjConfig["api"]["secret"], + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => '', + ), + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => '<div class="col-sm-12">' + . '<p>' . t('api-secret-hint') . '<br>' + . '<a href="#" class="btn btn-default" onclick="$(\'#input'.($i-2).'\').val(generateSecret(64)); return false">'.t("api-secret-generate").'</a>' + . '</p></div>', + ), + + // -------------------------------------------------- + // Tab rollout plugin + // -------------------------------------------------- + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => ' </div><div class="tab-pane" id="tab4"> + <p>' . t('deploy-rollout-plugin-hint') . '</p>', + ), + // select box for active rollout plugin + $aRollout['project-select'], + + // project based config + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => '' + . '<hr>' + .'<label class="col-sm-2">'.t('deploy-rollout-plugin-config') .'</label>' + .'<div class="col-sm-10">'. $aRollout['project-config'].'</div>' + ), + // -------------------------------------------------- + 'input' . $i++ => array( + 'type' => 'markup', + 'value' => ' </div><div class="tab-pane" id="tab5"> + <p>' . sprintf(t("class-project-info-setup-phaseinfos"), $this->getNextPhase()) . '</p>', + ), + ), + ), + ); + // -------------------------------------------------- + // Tab for phases + // -------------------------------------------------- + if ($aSelectForemanGroups) { + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '<strong>'.t("defaults-all-phases").'</strong><br><br>', + ); + $aForms["setup"]["form"]['input' . $i++] = $aSelectForemanGroups; + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '<br><br>', + ); + } + foreach (array_keys($this->getPhases()) as $sPhase) { + + $bActivePhase = $this->isActivePhase($sPhase); + $sUrl = array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["url"] : ""; + $sDeploymethod = array_key_exists("deploymethod", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploymethod"] : ""; + $sDeployhosts = array_key_exists("hosts", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["hosts"] : ""; + + /* + * task-1847 - reove adding ssh key + if($sDeployhosts){ + echo "$sDeployhosts<br>"; + if(!strpos($sDeployhosts, ",")){ + $sCmd=sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sDeployhosts, $sDeployhosts); + exec($sCmd . " 2>&1", $aOut); + echo "<pre>\$ $sCmd<br>" + . implode('<br>', $aOut) + ."</pre>" + ; + } + } + */ + $sDeploytimes = array_key_exists("deploytimes", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploytimes"] : ""; + $sDivId4PhaseSettings = 'divSettings' . $sPhase; + $sDivId4TargetHosts = 'divSettings' . $sPhase . 'hosts'; + + if ($aSelectForemanGroups) { + $iForemanHostgroup = (int) $this->_aPrjConfig['phases'][$sPhase]['foreman-hostgroup']; + $aSelectForemanHostGroup = array( + 'type' => 'select', + 'name' => 'phases[' . $sPhase . '][foreman-hostgroup]', + 'label' => $this->_oHtml->getIcon('foreman') . t("foreman-hostgroup"), + 'options' => array( + OPTION_DEFAULT => array( + 'label' => t('default') . ' (' . $sForemanHostgroupDefault . ')', + 'selected' => $iForemanHostgroup === OPTION_DEFAULT ? 'selected' : false, + ), + OPTION_NONE => array( + 'label' => t('none'), + 'selected' => $iForemanHostgroup === OPTION_NONE ? 'selected' : false, + ), + '' => array( + 'label' => '- - - - - - - - - - - - - - - - - - - - ', + ), + ), + ); + if (is_array($aForemanHostgroups) && count($aForemanHostgroups)) { + foreach ($aForemanHostgroups as $aItem) { + $aSelectForemanHostGroup['options'][$aItem['id']] = array( + 'label' => $aItem['title'], + 'selected' => ($iForemanHostgroup === $aItem['id']) ? 'selected' : false, + ); + } + } + } + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '' + // .'<pre>'.print_r($this->_aPrjConfig["phases"][$sPhase], 1).'</pre>' + /* + . '<a class="'.$sPhase.'">' + . t("phase") . ' ' . $sPhase + . '</a>' + */ + . '<table class="table">' + . '<tbody>' + . '<tr><th class="' . $sPhase . '">' . $this->_oHtml->getIcon('phase') . t("phase") . ' ' . $sPhase . '</th></tr>' + . '<tr><td class="' . ($bActivePhase ? $sPhase : '') . '">' + . '' + ); + + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'checkbox', + 'name' => 'phases[' . $sPhase . '][active]', + 'label' => t("phase-is-active"), + // 'value' => $bUsePuppet, + 'required' => false, + 'validate' => 'isastring', + // 'size' => 100, + // 'placeholder' => '...', + 'options' => array( + '1' => array( + 'label' => t("yes"), + 'checked' => $bActivePhase, + 'onclick' => '$(\'#' . $sDivId4PhaseSettings . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )', + ), + ), + ); + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '' + . '<div id="' . $sDivId4PhaseSettings . '" ' . ($bActivePhase ? '' : ' style="display: none;"') . '">' + ); + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'text', + 'name' => 'phases[' . $sPhase . '][url]', + 'label' => $this->_oHtml->getIcon('url') . t("url-project-website"), + 'value' => $sUrl, + // 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => 'https://' . $sPhase . '.[' . t("project") . '].[...]/', + ); + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'radio', + 'name' => 'phases[' . $sPhase . '][deploymethod]', + 'label' => $this->_oHtml->getIcon('method') . t("deploymethod"), + // 'value' => $bUsePuppet, + // 'required' => 'required', + 'validate' => 'isastring', + // 'size' => 100, + // 'placeholder' => '...', + 'options' => array( + 'none' => array( + 'label' => t("deploymethod-none"), + 'checked' => $sDeploymethod === "none", + 'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'none\' : \'block\') )', + ), + 'rolloutplugin' => array( + // 'label' => t("deploymethod-puppet").' - '. $this->oRolloutPlugin->getName(), + 'label' => t("deploymethod-rolloutplugin"), + 'checked' => $sDeploymethod === "rolloutplugin", + 'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )', + ), + /* + * see deploy method to handle an action + 'sshproxy' => array( + 'label' => t("deploymethod-sshproxy"), + 'checked' => $sDeploymethod==="sshproxy", + 'onclick' => '$(\'#'.$sDivId4TargetHosts.'\').css(\'display\', (this.checked ? \'block\' : \'none\') )', + ), + */ + ), + ); + + + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '' + . '<div id="' . $sDivId4TargetHosts . '" ' . ($sDeploymethod !== "none" ? '' : ' style="display: none;"') . '">' + ); + + // rollout plugin: phase specific overrides + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '' + // . '<hr>' + .'<label class="col-sm-2">'.t('deploy-rollout-plugin-config') .'</label>' + .'<div class="col-sm-10">'.$aRollout[$sPhase].'</div>' + ); + + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'text', + 'name' => 'phases[' . $sPhase . '][hosts]', + 'label' => $this->_oHtml->getIcon('host') . t("phase-targethosts"), + 'value' => $sDeployhosts, + // 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => 'FQDN1,FQDN2', + ); + + /* + if ($sPuppethost) { + + // add ssh host key + $sOut0 = shell_exec(sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sPuppethost, $sPuppethost)); + + $sCmd2 = 'ssh ' . $this->_aConfig["installPackages"]["user"] + . '@' . $sPuppethost + . ' ' . $this->_aConfig["installPackages"]["testcommand"]; + $sOut = 'skip'; + // $sOut = shell_exec($sCmd2); + // Check auf Versionsnummer - mehr als n Zeichen ist mutmasslich eine Fehlermeldung + if (strlen($sOut) > 7) { + $sMessages.=$this->getBox("error", sprintf(t("class-project-error-setup-sudo-pupet-agent-failed"), $sPhase, $sCmd, $sOut)); + $sOut = '<span class="error" title="' . $sCmd . '">' . $sOut . '</span>'; + } else { + $sOut = '<span class="ok">' . sprintf(t("class-project-info-setup-ssh-and-puppet-ok"), $sPuppethost) . '</span>'; + } + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '<div class="form-group">' + . '<label class="col-sm-2"> </label><div class="col-sm-10">' + . $sOut + . '</div></div>', + ); + } + */ + + // when to deploy + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'text', + 'name' => 'phases[' . $sPhase . '][deploytimes]', + 'label' => $this->_oHtml->getIcon('time') . t("deploytimes"), + 'value' => $sDeploytimes, + // 'required' => 'required', + 'validate' => 'isastring', + 'size' => 100, + 'placeholder' => isset($this->_aConfig["phases"][$sPhase]["deploytimes"]) ? implode(", ", $this->_aConfig["phases"][$sPhase]["deploytimes"]) : '', + ); + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '' + . '</div>' + ); + + if ($aSelectForemanGroups) { + $aForms["setup"]["form"]['input' . $i++] = $aSelectForemanHostGroup; + } + + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '' + . '</div>' + ); // close div for active phase + + + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '</td></tr></tbody></table>', + ); + } // END: loop over phases + + // -------------------------------------------------- + // Tab for raw data + // -------------------------------------------------- + + $sRolloutDebug='<hr>DEBUG:<br>'; + foreach (array_keys($this->getPhases()) as $sPhase) { + if ($this->isActivePhase($sPhase)){ + $sRolloutDebug.='<strong>'.$sPhase.'</strong>' + . '<pre>Config = '.print_r($this->oRolloutPlugin->getConfig($sPhase), 1).'</pre>' + . '<pre>Commands = '.print_r($this->oRolloutPlugin->getDeployCommands($sPhase), 1).'</pre>' + ; + } + } + + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'markup', + 'value' => '</div>' + + . '<div class="tab-pane" id="tab6">' + . '<br><pre>'.print_r($this->_aPrjConfig, 1).'</pre>' + . $sRolloutDebug + . '</div>' + + . '</div>' + . '</div>' + . '<div style="clear: both; margin-bottom: 1em;"></div>' + + + . '<hr>', + ); + $aForms["setup"]["form"]['input' . $i++] = array( + 'type' => 'submit', + 'name' => 'btnsave', + 'label' => t("save"), + 'value' => $this->_oHtml->getIcon('sign-ok').t("save"), + ); + + $oForm = new formgen($aForms); + return $sMessages . $oForm->renderHtml("setup"); + } + + /** + * return html code for the installed version in the repository + * @param boolean $bRefresh optional: refresh flag; default: use cached information + * @return string + */ + public function renderRepoInfo($bRefresh=false) { + $sReturn = ""; + switch ($this->_aPrjConfig["build"]["type"]) { + case "git": + + $aRepodata = $this->getRepoRevision($bRefresh); + if (array_key_exists("revision", $aRepodata)) { + $sReturn.=$this->_getChecksumDiv($aRepodata["revision"], + $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . (array_key_exists("branch", $aRepodata) ? $aRepodata["branch"] : '-') . '<br>' + . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aRepodata["revision"]) . '<br>' + . $this->_oHtml->getIconByType('comment') . t('commitmessage') . ':<br>' + ) + ."<pre>" . strip_tags($aRepodata["message"], '<br>') . "</pre>"; + } else { + $sReturn .= $this->_oHtml->getBox("error", sprintf(t('class-project-error-no-repoinfo'), $aRepodata["error"])) + . $this->renderLink("setup") . '<br>'; + } + + break; + + default: + $sReturn .= $this->_oHtml->getBox("error", sprintf(t('class-project-error-wrong-buildtype'), $this->_aPrjConfig["build"]["type"])); + } + if (array_key_exists("url", $this->_aPrjConfig["build"])) { + $sReturn.=t('repository-url') . ': ' . $this->_aPrjConfig["build"]["url"] . '<br>'; + } + if (array_key_exists("webaccess", $this->_aPrjConfig["build"])) { + $sReturn.=t('repository-access-browser') . ':<br><a href="' . $this->_aPrjConfig["build"]["webaccess"] . '">' . $this->_aPrjConfig["build"]["webaccess"] . '</a><br>'; + } + return $sReturn; + } + + /** + * get html code for a link to the commit + * (works for guithub and gitlab instances) + * + * @param string $sRevision + * @return string + */ + public function _renderRevision($sRevision) { + $sUrl = str_replace('/tree/master', '', $this->_aPrjConfig["build"]["webaccess"]) . '/commit/' . $sRevision; + return '<a href="' . $sUrl . '">' . $sRevision . '</a>'; + return $sUrl; + } + /** + * get html form with selectr for remote branches + * @param string $sActiveBranchname force active branch name + * @param bool $bIgnoreCache flag to ignore exiting cached data + * @return string + */ + public function renderSelectRemoteBranches($sActiveBranchname = false, $bIgnoreCache=false) { + $this->log(__FUNCTION__."(sActiveBranchname = $sActiveBranchname, bIgnoreCache = ".($bIgnoreCache ? 'true' : 'false').") start"); + $aReturn = array(); + $aRadios = array(); + $bFoundActive = false; + $i = 0; + if (!$this->_oVcs) { + $this->_initVcs(); + } + require_once("formgen.class.php"); + if (!$sActiveBranchname) { + $sActiveBranchname = $this->_sBranchname; + } + if ($this->_oVcs) { + if (!method_exists($this->_oVcs, "getRemoteBranches")) { + // the version control class does not have this method + return ''; + } + foreach ($this->_oVcs->getRemoteBranches($bIgnoreCache) as $aBranch) { + $sBranch = $aBranch['name']; + $aRadios[$sBranch] = array( + 'value' => $sBranch, + 'label' => $aBranch['label'], + ); + // if no param was given the first branch will be marked + if (!$sActiveBranchname) { + $sActiveBranchname = $sBranch; + } + if ($sBranch == $sActiveBranchname) { + $bFoundActive = true; + // $aRadios[$sBranch]['checked'] = 'checked'; + $aRadios[$sBranch]['selected'] = 'selected'; + } else { + // for SELECT we need the onclick even on select element + // not on the option (Chrome) + // $aRadios[$sBranch]['onclick'] = 'document.getElementById(\'submitBranch\').click()'; + } + }; + } + // no branches were found + if (count($aRadios) == 0) { + return ''; + } + + $aForms = array( + 'frmSelectBranch' => array( + 'meta' => array( + 'method' => 'POST', + 'action' => '?', + 'id' => 'frmSelectBranch', + ), + 'validate' => array(), + 'form' => array( + 'branchname' => array( + 'inline' => true, + 'type' => 'select', + 'onchange' => 'document.getElementById(\'submitBranch\').click()', + 'name' => 'branchname', + 'label' => '<strong>' . t('branch-select') . '</strong>', + 'validate' => 'isastring', + 'options' => $aRadios, + ), + ), + ), + ); + + // submit to switch branches - only if a selection is available + if (count($aRadios) > 1 || !$bFoundActive) { + $aForms['frmSelectBranch']['form']['submitBranch'] = array( + 'type' => 'submit', + 'name' => 'btnsave', + 'onclick' => 'showModalMessage(\'' . t('branch-switch') . '\'); ', + 'label' => t("change"), + 'value' => $this->_oHtml->getIcon('sign-ok').t("change"), + ); + } + + $oFrm = new formgen($aForms); + return $oFrm->renderHtml('frmSelectBranch') + . '<script>$("#submitBranch").hide();</script>'; + // return $oFrm->renderHtmlElement('dummy',$aFormData); + } + + /** + * return html code for a list of all built packages and their usage + * @return string + */ + public function renderVersionUsage() { + $sReturn = false; + $sRowHead1 = false; + $sRowHead2 = '<td></td>'; + + $aAllVersions = $this->_getVersionUsage(); + if (!count($aAllVersions)) { + return $this->_oHtml->getBox("info", t('class-project-info-no-package')); + } + + foreach ($this->getActivePhases() as $sPhase) { + $sRowHead1.='<th class="' . $sPhase . '" colspan="' . (count($this->_aPlaces) + 1) . '">' . $sPhase . '</th>'; + $sRowHead2.='<td></td>' . $this->renderPlacesAsTd($sPhase); + } + + krsort($aAllVersions); + foreach ($aAllVersions as $sVersion => $aData) { + $sReturn.='<tr>'; + + $sInfos = $this->renderInfoLink($aData["info"], array('hpos' => 'left')); + $sReturn.='<td>' + . $this->_getChecksumDiv( + $aData['info']['revision'], + $this->_oHtml->getIconByType('calendar') . t('build-from') . ': ' . $sVersion .'<br>' + . $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aData['info']["branch"] . '<br>' + . $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aData['info']["revision"]) . '<br>' + ) + . '</td><td>' + . ' ' . $sInfos . ' ' + . '</td>' + ; + + foreach ($this->getActivePhases() as $sPhase) { + $sTLine = ''; + $bCanRollback = $aData["rollback"][$sPhase]; + + // $sReturn.=$aData["rollback"][$sPhase] ? '<td>'.$this->renderLink("rollback", $sPhase, $sVersion).'</td>' : '<td>Rollback NOT possible</td>'; + // $sReturn.=$aData["rollback"][$sPhase] ? '<td> Y </td>' : '<td> N </td>'; + $sReturn.='<td> </td>'; + + foreach (array_keys($this->_aPlaces) as $sPlace) { + $bFound = false; + $sReturn.=$aData["usage"][$sPhase][$sPlace] + ? '<td class="' . $sPhase . '" style="text-align: center;">' + . $this->_getChecksumDiv($aData['info']['revision'], 'X') + . '</td>' + : '<td> </td>' + ; + } + } + $sReturn.='</tr>'; + } + + $sReturn = t('class-project-info-table-packages') . '<br><br>' + . '<table>' + . '<thead><tr><td>Version</td><td></td>' + . $sRowHead1 + . '</tr><tr><td>' + . $sRowHead2 + . '</tr></thead>' + . '<tbody>' + . $sReturn + . '</tbody>' + . '</table>'; + return $sReturn; + } + + /** + * render graphical overview of process (in project overview) + * @return string + */ + public function renderVisual() { + $sReturn = ''; + $sContinue = '<span style="font-size: 300%; color:#ace;">»»</span><br><br>'; + + $aBranches=$this->getRemoteBranches(); + if(!is_array($aBranches)){ + return t("project-setup-incomplete"); + } + + $sRepoBar = ''; + /* + Speedup: + + $aRepodata = $this->getRepoRevision(); + if (array_key_exists("revision", $aRepodata)) { + $sRepoBar = $this->_getChecksumDiv($aRepodata["revision"]); + } else { + $sRepoBar = '<span class="error">' . t("error") . '</span>'; + } + */ + + $sPackagebar = ''; + $aVersions = $this->_getVersionUsage(); + foreach ($aVersions as $sVersion => $aData) { + $sBar = $aData["info"]["revision"] ? $this->_getChecksumDiv($aData["info"]["revision"]) : ''; + $sPackagebar.='<span title="' . $sVersion . '" style="float: left; background:#eee; height: 3px; width:' . (100 / count($aVersions)) . '%">' . $sBar . ' </span>'; + } + + $sPhaseImg = ''; + $sLastPhase = ''; + foreach ($this->getActivePhases() as $sPhase) { + if ($sPhaseImg) { + $sAction = $sContinue; + if ($this->canAcceptPhase($sLastPhase)) { + $sAction .= $this->renderLink("accept", $sLastPhase); + } + $sPhaseImg.='<div class="action">' . $sAction . '</div>'; + } + $sLastPhase = $sPhase; + + $sFullbar = ''; + foreach (array_keys($this->_aPlaces) as $sPlace) { + $sFullbar.='<span title="' . $this->_aPlaces[$sPlace] . '" style="float: left; background:#eee; height: 3px; width:' . (100 / count($this->_aPlaces)) . '%">' . $this->_renderBar($sPhase, $sPlace) . ' </span>'; + } + // $sDetail = $sFullbar . '<br><a href="#h3phases" class="scroll-link">' . $sPhase . '</a>'; + $sDetail = $sFullbar . '<br>' . $sPhase; + + $sPhaseImg.=' + <div class="process ' . $sPhase . '"> + <div class="details">' . $sDetail . ' </div> + <div><img src="/deployment/images/process/bg_phase.png" alt="' . t("phase") . ' ' . $sPhase . '"></div> + </div>'; + } + $sReturn = ' + <div class="visualprocess"> + <div class="process box"> + <div class="title">' . $this->_oHtml->getIcon('repository') . t("versioncontrol") . '</div> + <div class="details"> + ' . $sRepoBar . '<br> + <!-- + <a href="#h3repo" class="scroll-link">' . t("repositoryinfos") . '</a><br> + --> + ' . t("repositoryinfos") . '<br> + ' . $this->_aPrjConfig["build"]["type"] . '</strong> ' . preg_replace('/.*\@(.*):.*/', '($1)', $this->_aPrjConfig["build"]["url"]) + . ': <strong title="' . t('branch-select') . '">' . count($aBranches) . '</strong>' + . '<br> + </div> + <div> + <img src="/deployment/images/process/bg_vcs.png" alt="' . t("versioncontrol") . '"> + </div> + </div> + + <div class="process"> + <div class="title"> </div> + <div class="action">' . $sContinue . t("build-hint-overview") . '<br><br>' . ($this->canAcceptPhase() ? $this->renderLink("build") : '') . '</div> + </div> + + + <div class="process box"> + <div class="title">' . $this->_oHtml->getIcon('package') . t("archive") . '</div> + <div class="details"> + ' . $sPackagebar . '<br> + <!-- + <a href="#h3versions" class="scroll-link">' . t("packages") . '</a><br> + --> + ' . t("packages") . '<br> + (<strong>' . count($this->_getVersionUsage()) . '</strong>) + </div> + <div><img src="/deployment/images/process/bg_archive.png" alt="' . t("archive") . '"></div> + </div> + + <div class="process"> + <div class="title"> </div> + <div class="action">'.$sContinue . sprintf(t("queue-hint-overview"), $this->getNextPhase()).'</div> + </div> + + <div class="process phases box"> + <div class="title">' . $this->_oHtml->getIcon('phase') . t("phases") . '</div> + ' . ($sPhaseImg ? $sPhaseImg : '<div class="process">' . t("none") . '</div>') . ' + </div> + </div> + '; + + return $sReturn; + } + +} diff --git a/public_html/deployment/classes/projectlist.class.php b/public_html/deployment/classes/projectlist.class.php index 92128f53..71a31dc9 100644 --- a/public_html/deployment/classes/projectlist.class.php +++ b/public_html/deployment/classes/projectlist.class.php @@ -11,7 +11,7 @@ ###################################################################### */ require_once 'base.class.php'; -require_once 'project.class.php'; +require_once 'project_gui.class.php'; /** * class for project overview @@ -93,7 +93,7 @@ class projectlist extends base{ ksort($aProjectLabels); foreach (array_values($aProjectLabels) as $sPrj) { - $oPrj = new project($sPrj); + $oPrj = new projectgui($sPrj); $sPrjFilter.='<option value="' . $sPrj . '">' . $oPrj->getLabel() . '</option>'; $sOutPhases = ''; diff --git a/public_html/deployment/pages/act_accept.php b/public_html/deployment/pages/act_accept.php index 7241d8ee..974e87fa 100644 --- a/public_html/deployment/pages/act_accept.php +++ b/public_html/deployment/pages/act_accept.php @@ -10,10 +10,10 @@ 2013-11-08 Axel <axel.hahn@iml.unibe.ch> ###################################################################### */ -require_once("./classes/project.class.php"); +require_once("./classes/project_gui.class.php"); // --- Checks -$oPrj = new project($aParams["prj"]); +$oPrj = new projectgui($aParams["prj"]); if (array_key_exists("par3", $aParams)) { $sPhase = $aParams["par3"]; diff --git a/public_html/deployment/pages/act_build.php b/public_html/deployment/pages/act_build.php index 55412973..51898dbd 100644 --- a/public_html/deployment/pages/act_build.php +++ b/public_html/deployment/pages/act_build.php @@ -12,12 +12,12 @@ 2013-11-08 Axel <axel.hahn@iml.unibe.ch> ###################################################################### */ -require_once("./classes/project.class.php"); +require_once("./classes/project_gui.class.php"); require_once("./classes/formgen.class.php"); set_time_limit(0); // --- Checks -$oPrj = new project($aParams["prj"]); +$oPrj = new projectgui($aParams["prj"]); $sOut = ''; diff --git a/public_html/deployment/pages/act_delete.php b/public_html/deployment/pages/act_delete.php index 6c8a94da..a156e9fb 100644 --- a/public_html/deployment/pages/act_delete.php +++ b/public_html/deployment/pages/act_delete.php @@ -13,10 +13,10 @@ 2014-03-24 Axel <axel.hahn@iml.unibe.ch> ###################################################################### */ -require_once("./classes/project.class.php"); +require_once("./classes/project_gui.class.php"); require_once("./classes/formgen.class.php"); -$oPrj = new project($sPrj); +$oPrj = new projectgui($sPrj); $sOut = '<h3>' . t('page-delete-project-info') . '</h3>'; diff --git a/public_html/deployment/pages/act_deploy.php b/public_html/deployment/pages/act_deploy.php index 2d694e35..77f9b747 100644 --- a/public_html/deployment/pages/act_deploy.php +++ b/public_html/deployment/pages/act_deploy.php @@ -10,12 +10,12 @@ 2013-11-08 Axel <axel.hahn@iml.unibe.ch> ###################################################################### */ -require_once("./classes/project.class.php"); +require_once("./classes/project_gui.class.php"); require_once("./classes/formgen.class.php"); require_once("./inc_functions.php"); // --- Checks -$oPrj = new project($aParams["prj"]); +$oPrj = new projectgui($aParams["prj"]); $sOut = ''; if (array_key_exists("par3", $aParams)) { diff --git a/public_html/deployment/pages/act_overview.php b/public_html/deployment/pages/act_overview.php index 0cfe8e5c..3aca294e 100644 --- a/public_html/deployment/pages/act_overview.php +++ b/public_html/deployment/pages/act_overview.php @@ -29,8 +29,8 @@ if (!array_key_exists("prj", $aParams)) { // ---------------------------------------------------------------------- // overview of a single project // ---------------------------------------------------------------------- - require_once("./classes/project.class.php"); - $oPrj = new project($aParams["prj"]); + require_once("./classes/project_gui.class.php"); + $oPrj = new projectgui($aParams["prj"]); $iCountOfBranches=0; $iCountOfBuildErrors=count($oPrj->getBuildErrors()); diff --git a/public_html/deployment/pages/act_phase.php b/public_html/deployment/pages/act_phase.php index 647c274a..62a5538e 100644 --- a/public_html/deployment/pages/act_phase.php +++ b/public_html/deployment/pages/act_phase.php @@ -11,13 +11,13 @@ 2013-11-08 Axel <axel.hahn@iml.unibe.ch> ###################################################################### */ -require_once("./classes/project.class.php"); +require_once("./classes/project_gui.class.php"); require_once("./inc_functions.php"); require_once("./classes/config-replacement.class.php"); // --- Checks -$oPrj = new project($aParams["prj"]); +$oPrj = new projectgui($aParams["prj"]); $sOut = ''; if (isset($aParams["par3"])) { diff --git a/public_html/deployment/pages/act_setup.php b/public_html/deployment/pages/act_setup.php index ddee0847..82121eda 100644 --- a/public_html/deployment/pages/act_setup.php +++ b/public_html/deployment/pages/act_setup.php @@ -12,7 +12,7 @@ 2013-11-08 Axel <axel.hahn@iml.unibe.ch> ###################################################################### */ -require_once("./classes/project.class.php"); +require_once("./classes/project_gui.class.php"); require_once("./inc_functions.php"); $sOut = ''; @@ -37,8 +37,8 @@ $aMask=array( /** * hide entries in config array - * @param type $aMask - * @param type $aConfig + * @param array $aMask + * @param array $aConfig * @return type */ function maskEntries($aMask, $aConfig){ @@ -196,7 +196,7 @@ if ($aParams["prj"] == "all") { if ($aParams["par3"]=="new") { $sOut.='<h2>'.t("page-setup-info-new-project").'</h2>' . '<p>'.t("page-setup-info-new-project-introtext").'</p><hr>'; - $oPrj = new project(); + $oPrj = new projectgui(); if (array_key_exists("setupaction", $aParams) && $aParams["setupaction"] == "create") { $sError = $oPrj->create($aParams["id"]); @@ -329,7 +329,7 @@ if ($aParams["prj"] == "all") { // ------------------------------------------------------------ // setup page of a an existing project // ------------------------------------------------------------ - $oPrj = new project($aParams["prj"]); + $oPrj = new projectgui($aParams["prj"]); /* $sOut.='<div style="float: right">' // . 'aParams:<pre>'.print_r($aParams, true).'</pre>' -- GitLab