From 1eae54c17b4783fe10aa4be6b121997df780630c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E9=87=91=E5=8B=87?= Date: Fri, 9 Jun 2023 03:31:44 +0000 Subject: [PATCH] * Migrate admin of qucheng. --- config/config.php | 2 +- framework/helper.class.php | 13 + module/admin/config.php | 1 + module/admin/lang/en.php | 2 + module/admin/lang/menu.php | 5 + module/admin/lang/zh-cn.php | 2 + module/cne/lang/zh-cn.php | 28 + module/cne/model.php | 1204 ++++++++++++++++++++ module/common/lang/common.php | 1 + module/common/lang/menu.php | 1 + module/common/model.php | 75 ++ module/instance/model.php | 18 - module/system/control.php | 639 +++++++++++ module/system/css/dblist.css | 3 + module/system/css/editdomain.css | 1 + module/system/css/editldap.css | 1 + module/system/css/index.css | 7 + module/system/css/installldap.css | 1 + module/system/css/installsmtp.css | 1 + module/system/css/ldapview.css | 7 + module/system/css/ossview.css | 5 + module/system/css/smtpview.css | 1 + module/system/js/dblist.js | 22 + module/system/js/editdomain.js | 143 +++ module/system/js/editldap.js | 155 +++ module/system/js/editslb.js | 34 + module/system/js/editsmtp.js | 73 ++ module/system/js/installldap.js | 129 +++ module/system/js/installsmtp.js | 91 ++ module/system/js/ldapview.js | 127 +++ module/system/js/ossview.js | 33 + module/system/js/smtpview.js | 110 ++ module/system/lang/zh-cn.php | 170 +++ module/system/model.php | 943 +++++++++++++++ module/system/view/dashboard.html.php | 20 + module/system/view/dblist.html.php | 43 + module/system/view/domainview.html.php | 43 + module/system/view/editdomain.html.php | 97 ++ module/system/view/editldap.html.php | 32 + module/system/view/editslb.html.php | 58 + module/system/view/editsmtp.html.php | 32 + module/system/view/index.html.php | 76 ++ module/system/view/installldap.html.php | 31 + module/system/view/installsmtp.html.php | 31 + module/system/view/instancesblock.html.php | 43 + module/system/view/ldapform.html.php | 98 ++ module/system/view/ldapview.html.php | 132 +++ module/system/view/ossview.html.php | 69 ++ module/system/view/overviewblock.html.php | 32 + module/system/view/slbview.html.php | 38 + module/system/view/smtpform.html.php | 36 + module/system/view/smtpview.html.php | 60 + 52 files changed, 5000 insertions(+), 19 deletions(-) create mode 100644 module/cne/lang/zh-cn.php create mode 100644 module/cne/model.php create mode 100644 module/system/control.php create mode 100644 module/system/css/dblist.css create mode 100644 module/system/css/editdomain.css create mode 100644 module/system/css/editldap.css create mode 100644 module/system/css/index.css create mode 100644 module/system/css/installldap.css create mode 100644 module/system/css/installsmtp.css create mode 100644 module/system/css/ldapview.css create mode 100644 module/system/css/ossview.css create mode 100644 module/system/css/smtpview.css create mode 100644 module/system/js/dblist.js create mode 100644 module/system/js/editdomain.js create mode 100644 module/system/js/editldap.js create mode 100644 module/system/js/editslb.js create mode 100644 module/system/js/editsmtp.js create mode 100644 module/system/js/installldap.js create mode 100644 module/system/js/installsmtp.js create mode 100644 module/system/js/ldapview.js create mode 100644 module/system/js/ossview.js create mode 100644 module/system/js/smtpview.js create mode 100644 module/system/lang/zh-cn.php create mode 100644 module/system/model.php create mode 100644 module/system/view/dashboard.html.php create mode 100644 module/system/view/dblist.html.php create mode 100644 module/system/view/domainview.html.php create mode 100644 module/system/view/editdomain.html.php create mode 100644 module/system/view/editldap.html.php create mode 100644 module/system/view/editslb.html.php create mode 100644 module/system/view/editsmtp.html.php create mode 100644 module/system/view/index.html.php create mode 100644 module/system/view/installldap.html.php create mode 100644 module/system/view/installsmtp.html.php create mode 100644 module/system/view/instancesblock.html.php create mode 100644 module/system/view/ldapform.html.php create mode 100644 module/system/view/ldapview.html.php create mode 100644 module/system/view/ossview.html.php create mode 100644 module/system/view/overviewblock.html.php create mode 100644 module/system/view/slbview.html.php create mode 100644 module/system/view/smtpform.html.php create mode 100644 module/system/view/smtpview.html.php diff --git a/config/config.php b/config/config.php index a5804d5c6c..bfd818b13c 100644 --- a/config/config.php +++ b/config/config.php @@ -218,7 +218,7 @@ $config->CNE->app->domain = 'dev.haogs.cn'; $config->cloud = new stdclass; $config->cloud->api = new stdclass; -$config->cloud->api->host = 'http://cne-market.internal-pre.chandao.net'; +$config->cloud->api->host = 'https://api.qucheng.com'; $config->cloud->api->auth = 'X-Auth-Token'; $config->cloud->api->token = 'gwaN4KynqNqQoPD7eN8s'; // Please set token in my.php. $config->cloud->api->headers = array('Content-Type: application/json'); diff --git a/framework/helper.class.php b/framework/helper.class.php index e3df1254ca..968b1a13c9 100644 --- a/framework/helper.class.php +++ b/framework/helper.class.php @@ -231,6 +231,19 @@ class helper extends baseHelper ); } + /** + * Process traffic. + * + * @param float $traffic + * @param int $precision + * @access public + * @return float + */ + public static function formatKB($traffic, $precision = 2) + { + return round($traffic / (1024 * 1024), $precision) >= 1 ? round($traffic / (1024 * 1024), $precision) . 'GB' : (round($traffic / 1024, $precision) >= 1 ? round($traffic / 1024, $precision) . 'MB' : round($traffic, $precision) . 'KB'); + } + /** * Trim version to xuanxuan version format. * diff --git a/module/admin/config.php b/module/admin/config.php index fed9cf56bf..94da4c0837 100755 --- a/module/admin/config.php +++ b/module/admin/config.php @@ -84,6 +84,7 @@ $config->admin->helpURL['message'] = 'https://www.zentao.net/book/zentaopms/em $config->admin->helpURL['extension'] = 'https://www.zentao.net/book/zentaopms/536.html'; $config->admin->helpURL['dev'] = 'https://www.zentao.net/book/zentaopms/537.html'; $config->admin->helpURL['convert'] = 'https://www.zentao.net/book/zentaopms/656.html'; +$config->admin->helpURL['platform'] = 'https://www.zentao.net/book/zentaopms/656.html'; $config->admin->navsGroup['feature']['my'] = ',todo,block,'; $config->admin->navsGroup['feature']['product'] = ',product,story,productplan,release,'; diff --git a/module/admin/lang/en.php b/module/admin/lang/en.php index c9ac499fcf..04d62f7ef9 100755 --- a/module/admin/lang/en.php +++ b/module/admin/lang/en.php @@ -180,6 +180,8 @@ $lang->admin->menuSetting['dev']['name'] = 'Develop'; $lang->admin->menuSetting['dev']['desc'] = 'Support for secondary development of the system.'; $lang->admin->menuSetting['convert']['name'] = 'Data Import'; $lang->admin->menuSetting['convert']['desc'] = 'Data import from third-party systems.'; +$lang->admin->menuSetting['platform']['name'] = 'Platform'; +$lang->admin->menuSetting['platform']['desc'] = 'Settings of platform.'; $lang->admin->updateDynamics = 'Dynamics'; $lang->admin->updatePatch = 'Patch'; diff --git a/module/admin/lang/menu.php b/module/admin/lang/menu.php index bf0448e0e7..54cae97c06 100644 --- a/module/admin/lang/menu.php +++ b/module/admin/lang/menu.php @@ -44,6 +44,11 @@ $lang->admin->menuList->convert['desc'] = $lang->admin->menuSetting['convert'][ $lang->admin->menuList->convert['link'] = 'convert|convertjira'; $lang->admin->menuList->convert['order'] = 50; +$lang->admin->menuList->platform['name'] = $lang->admin->menuSetting['platform']['name']; +$lang->admin->menuList->platform['desc'] = $lang->admin->menuSetting['platform']['desc']; +$lang->admin->menuList->platform['link'] = 'system|platform'; +$lang->admin->menuList->platform['order'] = 55; + $lang->admin->menuList->system['subMenu']['mode'] = array('link' => "{$lang->custom->mode}|custom|mode|"); $lang->admin->menuList->system['subMenu']['trash'] = array('link' => "{$lang->action->trash}|action|trash|"); $lang->admin->menuList->system['subMenu']['safe'] = array('link' => "{$lang->security}|admin|safe|", 'alias' => 'checkweak,resetpwdsetting', 'links' => array('admin|resetpwdsetting|', 'admin|checkweak|')); diff --git a/module/admin/lang/zh-cn.php b/module/admin/lang/zh-cn.php index a1014bb979..b3b051218b 100755 --- a/module/admin/lang/zh-cn.php +++ b/module/admin/lang/zh-cn.php @@ -180,6 +180,8 @@ $lang->admin->menuSetting['dev']['name'] = '二次开发'; $lang->admin->menuSetting['dev']['desc'] = '支持对系统进行二次开发。'; $lang->admin->menuSetting['convert']['name'] = '数据导入'; $lang->admin->menuSetting['convert']['desc'] = '第三方系统的数据导入。'; +$lang->admin->menuSetting['platform']['name'] = '平台设置'; +$lang->admin->menuSetting['platform']['desc'] = '平台功能的相关配置。'; $lang->admin->updateDynamics = '更新动态'; $lang->admin->updatePatch = '补丁更新'; diff --git a/module/cne/lang/zh-cn.php b/module/cne/lang/zh-cn.php new file mode 100644 index 0000000000..57539e5198 --- /dev/null +++ b/module/cne/lang/zh-cn.php @@ -0,0 +1,28 @@ +CNE->InstallSuccess = '安装成功'; +$lang->CNE->InstallFailure = '安装失败'; +$lang->CNE->serverError = 'CNE服务器出错'; + +$lang->CNE->statusList = array(); +$lang->CNE->statusList['normal'] = '正常'; +$lang->CNE->statusList['abnormal'] = '异常'; +$lang->CNE->statusList['stopped'] = '关闭'; +$lang->CNE->statusList['unknown'] = '无数据'; + +$lang->CNE->statusIcons = array(); +$lang->CNE->statusIcons['normal'] = ""; +$lang->CNE->statusIcons['abnormal'] = ""; +$lang->CNE->statusIcons['stopped'] = ""; +$lang->CNE->statusIcons['unknown'] = ""; + +$lang->CNE->errorList = array(); +//$lang->CNE->errorList[400] = '不能包含特殊字符'; +$lang->CNE->errorList[400] = '请求集群接口失败'; +$lang->CNE->errorList[404] = '服务不存在'; +$lang->CNE->errorList[40004] = '证书与域名不匹配'; +$lang->CNE->errorList[41001] = '证书过期'; +$lang->CNE->errorList[41002] = '证书不匹配'; +$lang->CNE->errorList[41003] = '证书链不完整'; +$lang->CNE->errorList[41004] = '私钥与证书不匹配'; +$lang->CNE->errorList[41005] = '证书解析失败'; +$lang->CNE->errorList[41006] = '密钥解析失败'; diff --git a/module/cne/model.php b/module/cne/model.php new file mode 100644 index 0000000000..1cc8f9aafb --- /dev/null +++ b/module/cne/model.php @@ -0,0 +1,1204 @@ + + * @package CNE + * @version $Id$ + * @link https://www.qucheng.com + */ +class cneModel extends model +{ + protected $error; + + /** + * Construct function: set api headers. + * + * @param string $appName + * @access public + * @return void + */ + public function __construct($appName = '') + { + parent::__construct($appName); + + $this->error = new stdclass; + + global $config, $app; + $config->CNE->api->headers[] = "{$config->CNE->api->auth}: {$config->CNE->api->token}"; + $config->cloud->api->headers[] = "{$config->cloud->api->auth}: {$config->cloud->api->token}"; + + if($config->cloud->api->switchChannel && $app->session->cloudChannel) + { + $config->cloud->api->channel = $app->session->cloudChannel; + $config->CNE->api->channel = $app->session->cloudChannel; + } + } + + /** + * Get all instance of app in cluster. + * + * @access public + * @return array + */ + public function instanceList() + { + $apiUrl = "/api/cne/system/app-full-list"; + $result = $this->apiGet($apiUrl, array(), $this->config->CNE->api->headers); + if(empty($result) || $result->code != 200 || empty($result->data)) return array(); + + $instanceList = $result->data; + return array_combine(array_column($instanceList, 'name'), $instanceList); + } + + /** + * Update platform domain. + * + * @param string $domain + * @access public + * @return bool + */ + public function updatePlatformDomain($domain) + { + $instance = new stdclass; + $instance->k8name = 'qucheng'; + $instance->chart = 'qucheng'; + + $instance->spaceData = new stdclass; + $instance->spaceData->k8space = $this->config->k8space; + + $settings = new stdclass; + $settings->settings_map = new stdclass; + $settings->settings_map->env = new stdclass; + $settings->settings_map->env->APP_DOMAIN = $domain; + + return $this->updateConfig($instance, $settings); + } + + /** + * Upgrade platform. + * + * @param string $toVersion + * @access public + * @return bool + */ + public function upgradePlatform($toVersion) + { + $apiUrl = "/api/cne/system/update"; + $result = $this->apiPost($apiUrl, array('version' => $toVersion, 'channel' => $this->config->CNE->api->channel), $this->config->CNE->api->headers); + if($result && $result->code == 200) return true; + + return false; + } + + /** + * Upgrade or degrade platform version. + * + * @param string $version + * @access public + * @return bool + */ + public function setPlatformVersion($version) + { + $instance = new stdclass; + $instance->k8name = 'qucheng'; + $instance->chart = 'qucheng'; + + $instance->spaceData = new stdclass; + $instance->spaceData->k8space = $this->config->k8space; + + return $this->upgradeToVersion($instance, $version); + } + + /** + * Upgrade app instance to version. + * + * @param object $instance + * @param string $toVersion + * @access public + * @return bool + */ + public function upgradeToVersion($instance, $toVersion = '') + { + $setting = array(); + $setting['cluster'] = ''; + $setting['namespace'] = $instance->spaceData->k8space; + $setting['name'] = $instance->k8name; + $setting['channel'] = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + $setting['chart'] = $instance->chart; + $setting['version'] = $toVersion; + + $apiUrl = "/api/cne/app/settings"; + $result = $this->apiPost($apiUrl, $setting, $this->config->CNE->api->headers); + if($result && $result->code == 200) return true; + + return false; + } + + /** + * Update instance config. For example: cpu, memory size, LDAP settings... + * + * @param object $instance + * @param object $settings + * @access public + * @return bool + */ + public function updateConfig($instance, $settings) + { + $apiParams = array(); + $apiParams['cluster'] = ''; + $apiParams['namespace'] = $instance->spaceData->k8space; + $apiParams['name'] = $instance->k8name; + $apiParams['channel'] = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + $apiParams['chart'] = $instance->chart; + + if(isset($instance->version)) $apiParams['version'] = $instance->version; + if(isset($settings->force_restart)) $apiParams['force_restart'] = $settings->force_restart; + if(isset($settings->settings_map)) $apiParams['settings_map'] = $settings->settings_map; + if(isset($settings->settings_snippets)) $apiParams['settings_snippets'] = $settings->settings_snippets; + + $apiUrl = "/api/cne/app/settings"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return true; + + return false; + } + + /** + * Config QLB (Server Load Balancing). + * + * @param object $settings + * @param string $channel + * @access public + * @return bool + */ + public function configQLB($settings, $channel = '') + { + $apiParams = array(); + $apiParams['cluster'] = ''; + $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel; + $apiParams['namespace'] = $settings->namespace; + $apiParams['name'] = $settings->name; + $apiParams['ippool'] = $settings->ippool; + + $apiUrl = "/api/cne/system/qlb/config"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return true; + + return false; + } + + /** + * Get Qucheng Load Balancer Info + * + * @param string $name + * @param string $namespace + * @access public + * @return object + */ + public function getQLBInfo($name, $namespace) + { + $apiParams = array(); + $apiParams['cluster'] = ''; + $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel; + $apiParams['namespace'] = $namespace; + $apiParams['name'] = $name; + + $apiUrl = "/api/cne/system/qlb/config"; + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return $result->data; + + return null; + } + + /** + * Valid Certificate. + * + * @param string $certName + * @param string $pem + * @param string $key + * @param string $domain + * @access public + * @return bool + */ + public function validateCert($certName, $pem, $key, $domain) + { + $apiParams = array(); + $apiParams['name'] = $certName; + $apiParams['certificate_pem'] = $pem; + $apiParams['private_key_pem'] = $key; + + $apiUrl = "/api/cne/system/tls/validator"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code != 200) return $result; + + $match = false; + foreach($result->data->sans as $domainPattern) + { + if(stripos($domainPattern, $domain) !== false) + { + $match = true; + break; + } + } + if(!$match) + { + $result->code = 40004; + $result->message = zget($this->lang->CNE->errorList, 40004); + } + + return $result; + } + + /** + * Upload cert + * + * @param object $cert + * @param string $channel + * @access public + * @return object + */ + public function uploadCert($cert, $channel = '') + { + $apiParams = array(); + $apiParams['cluster'] = ''; + $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel; + $apiParams['name'] = $cert->name; + $apiParams['certificate_pem'] = $cert->certificate_pem; + $apiParams['private_key_pem'] = $cert->private_key_pem; + + $apiUrl = "/api/cne/system/tls/upload"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + //if($result && $result->code == 200) return $result->data; + + return $result; + } + + /** + * Upload cert + * + * @param string $certName + * @param string $channel + * @access public + * @return object|null success: return cert info, fail: return null. + */ + public function certInfo($certName, $channel = '') + { + $apiParams = array(); + $apiParams['cluster'] = ''; + $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel; + $apiParams['name'] = $certName; + + $apiUrl = "/api/cne/system/tls/info"; + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return $result->data; + + return null; + } + + /** + * Get default username and password of app. + * + * @param object $instance + * @param string $cluster + * @access public + * @return object|null + */ + public function getDefaultAccount($instance, $cluster = '', $component = '') + { + $apiUrl = '/api/cne/app/account?channel='. (empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel); + $apiParams = array(); + $apiParams['name'] = $instance->k8name; + $apiParams['namespace'] = $instance->spaceData->k8space; + $apiParams['cluster'] = $cluster; + if($component) $apiParams['component'] = $component; + + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers, $this->config->CNE->api->host); + if(!isset($result->code) || $result->code != 200) return null; + + $account = $result->data; + if(isset($account->username) && $account->username && isset($account->password) && $account->password) return $account; + + return null; + } + + /** + * Get suffix domain. + * + * @access public + * @return string + */ + public function sysDomain() + { + $customDomain = $this->loadModel('setting')->getItem('owner=system&module=common§ion=domain&key=customDomain'); + if($customDomain) return $customDomain; + + return getenv('APP_DOMAIN') ? getenv('APP_DOMAIN') : $this->config->CNE->app->domain; + } + + /** + * Get domain. + * + * @param object $instance + * @param string $cluster + * @param string $component + * @access public + * @return object|null + */ + public function getDomain($instance, $cluster = '', $component = '') + { + $apiUrl = '/api/cne/app/domain?channel='. (empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel); + $apiParams = array(); + $apiParams['name'] = $instance->k8name; + $apiParams['namespace'] = $instance->spaceData->k8space; + $apiParams['cluster'] = $cluster; + if($component) $apiParams['component'] = $component; + + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers, $this->config->CNE->api->host); + if(!isset($result->code) || $result->code != 200) return null; + + return $result->data; + } + + /** + * Get cluster metrics of CNE platform. + * + * @param string $cluster + * @access public + * @return object + */ + public function cneMetrics($cluster = '') + { + $metrics = new stdclass; + $metrics->cpu = new stdclass; + $metrics->cpu->usage = 0; + $metrics->cpu->capacity = 0; + $metrics->cpu->allocatable = 0; + $metrics->cpu->rate = 0; + + $metrics->memory = new stdclass; + $metrics->memory->usage = 0; + $metrics->memory->capacity = 0; + $metrics->memory->allocatable = 0; + $metrics->memory->rate = 0; + + $statistics = new stdclass; + $statistics->status = 'unknown'; + $statistics->node_count = 0; + $statistics->metrics = $metrics; + + $apiUrl = "/api/cne/statistics/cluster"; + $result = $this->apiGet($apiUrl, array('cluster' => $cluster), $this->config->CNE->api->headers); + if($result->code != 200) return $statistics; + + $statistics = $result->data; + + $statistics->metrics->cpu->usage = max(round($statistics->metrics->cpu->usage, 4), 0); + $statistics->metrics->cpu->capacity = max(round($statistics->metrics->cpu->capacity, 4), $statistics->metrics->cpu->usage); + $statistics->metrics->cpu->allocatable = round($statistics->metrics->cpu->allocatable, 4); + $statistics->metrics->cpu->rate = $statistics->metrics->cpu->capacity > 0 ? round( $statistics->metrics->cpu->usage / $statistics->metrics->cpu->capacity * 100, 2) : 0; + $statistics->metrics->cpu->rate = min($statistics->metrics->cpu->rate, 100); + + $statistics->metrics->memory->usage = max(round($statistics->metrics->memory->usage, 4), 0); + $statistics->metrics->memory->capacity = max($statistics->metrics->memory->capacity, $statistics->metrics->memory->usage); + $statistics->metrics->memory->rate = $statistics->metrics->memory->capacity > 0 ? round($statistics->metrics->memory->usage / $statistics->metrics->memory->capacity * 100, 2) : 0; + $statistics->metrics->memory->rate = min($statistics->metrics->memory->rate, 100); + return $statistics; + } + + /** + * Get instance metrics. + * + * @param array $instances + * @access public + * @return object + */ + public function instancesMetrics($instances) + { + $instancesMetrics = array(); + + $apiData = array('cluster' => '', 'apps' => array()); + foreach($instances as $instance) + { + if($instance->source == 'external') continue; + + $appData = new stdclass; + $appData->name = $instance->k8name; + $appData->namespace = $instance->spaceData->k8space; + $apiData['apps'][] = $appData; + + $instanceMetric = new stdclass; + $instanceMetric->id = $instance->id; + $instanceMetric->name = $instance->k8name; + $instanceMetric->namespace = $instance->spaceData->k8space; + + $instanceMetric->cpu = new stdclass; + $instanceMetric->cpu->limit = 0; + $instanceMetric->cpu->usage = 0; + $instanceMetric->cpu->rate = 0; + + $instanceMetric->memory = new stdclass; + $instanceMetric->memory->limit = 0; + $instanceMetric->memory->usage = 0; + $instanceMetric->memory->rate = 0; + + $instancesMetrics[$instance->k8name] = $instanceMetric; + } + + $apiUrl = "/api/cne/statistics/app"; + $result = $this->apiPost($apiUrl, $apiData, $this->config->CNE->api->headers); + if(!isset($result->code) || $result->code != 200)return array_combine(array_column($instancesMetrics, 'id'), $instancesMetrics); + + foreach($result->data as $k8sMetric) + { + if(!isset($k8sMetric->metrics)) continue; + + $instancesMetrics[$k8sMetric->name]->cpu->usage = isset($k8sMetric->metrics->cpu) && isset($k8sMetric->metrics->cpu->usage) ? round($k8sMetric->metrics->cpu->usage, 4) : 0; + $instancesMetrics[$k8sMetric->name]->cpu->usage = max($instancesMetrics[$k8sMetric->name]->cpu->usage, 0); + $instancesMetrics[$k8sMetric->name]->cpu->limit = isset($k8sMetric->metrics->cpu) && isset($k8sMetric->metrics->cpu->limit) ? round($k8sMetric->metrics->cpu->limit, 4) : 0; + $instancesMetrics[$k8sMetric->name]->cpu->limit = max($instancesMetrics[$k8sMetric->name]->cpu->limit, $instancesMetrics[$k8sMetric->name]->cpu->usage); + $instancesMetrics[$k8sMetric->name]->cpu->rate = $instancesMetrics[$k8sMetric->name]->cpu->limit > 0 ? round($instancesMetrics[$k8sMetric->name]->cpu->usage / $instancesMetrics[$k8sMetric->name]->cpu->limit * 100, 2) : 0; + + $instancesMetrics[$k8sMetric->name]->memory->usage = isset($k8sMetric->metrics->memory) && isset($k8sMetric->metrics->memory->usage) ? $k8sMetric->metrics->memory->usage : 0; + $instancesMetrics[$k8sMetric->name]->memory->usage = max($instancesMetrics[$k8sMetric->name]->memory->usage, 0); + $instancesMetrics[$k8sMetric->name]->memory->limit = isset($k8sMetric->metrics->memory) && isset($k8sMetric->metrics->memory->limit) ? $k8sMetric->metrics->memory->limit : 0; + $instancesMetrics[$k8sMetric->name]->memory->limit = max( $instancesMetrics[$k8sMetric->name]->memory->limit, $instancesMetrics[$k8sMetric->name]->memory->usage); + $instancesMetrics[$k8sMetric->name]->memory->rate = $instancesMetrics[$k8sMetric->name]->memory->limit > 0 ? round($instancesMetrics[$k8sMetric->name]->memory->usage / $instancesMetrics[$k8sMetric->name]->memory->limit * 100, 2) : 0; + } + + return array_combine(array_column($instancesMetrics, 'id'), $instancesMetrics); + } + + /** + * Print CPU usage. + * + * @param object $metrics + * @static + * @access public + * @return viod + */ + public static function printCpuUsage($metrics) + { + $rate = $metrics->rate; + + $tip = "{$rate}% = {$metrics->usage} / {$metrics->capacity}"; + commonModel::printProgressBar($rate, '', $tip, 'percent'); + } + + /** + * Print memory usage. + * + * @param object $metrics + * @static + * @access public + * @return viod + */ + public static function printMemUsage($metrics) + { + $rate = $metrics->rate; + + $tip = "{$rate}% = " . helper::formatKB($metrics->usage / 1024) . ' / ' . helper::formatKB($metrics->capacity / 1024); + commonModel::printProgressBar($rate, '', $tip, 'tip'); + } + + /** + * Backup service in k8s cluster. + * + * @param object $instance + * @access public + * @return object + */ + public function backup($instance, $account) + { + $apiParams = new stdclass; + $apiParams->username = $account; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + + $apiUrl = "/api/cne/app/backup"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Stauts of backup progress. + * + * @param object $instance + * @param object $backup + * @access public + * @return object + */ + public function backupStatus($instance, $backup) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + $apiParams->backup_name = $backup->backupName; + $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + + $apiUrl = "/api/cne/app/backup/status"; + return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Backup list. + * + * @param object $instance + * @access public + * @return object + */ + public function backupList($instance) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + + $apiUrl = "/api/cne/app/backups"; + return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * (not Finish: waiting cne api) Delete backup. + * + * @param object $instance + * @param string $backupName + * @access public + * @return bool + */ + public function deleteBackup($instance, $backupName) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + $apiParams->backup_name = $backupName; + $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + + $apiUrl = "/api/cne/app/backup/remove"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return true; + + return false; + } + + /** + * Backup service in k8s cluster. + * + * @param object $instance + * @param object $backupName + * @param string $account + * @access public + * @return object + */ + public function restore($instance, $backupName, $account) + { + $apiParams = new stdclass; + $apiParams->username = $account; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + $apiParams->backup_name = $backupName; + $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + + $apiUrl = "/api/cne/app/restore"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Stauts of restore progress. + * + * @param object $instance + * @param object $restore + * @access public + * @return object + */ + public function restorestatus($instance, $restore) + { + $apiparams = new stdclass; + $apiparams->cluster = ''; + $apiparams->namespace = $instance->spacedata->k8space; + $apiparams->name = $instance->k8name; + $apiparams->restore_name = $restore->restorename; + $apiparams->channel = empty($instance->channel) ? $this->config->cne->api->channel : $instance->channel; + + $apiurl = "/api/cne/app/restore/status"; + return $this->apiget($apiurl, $apiparams, $this->config->cne->api->headers); + } + + /** + * Start an app instance. + * + * @param object $apiParams + * @access public + * @return object + */ + public function startApp($apiParams) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/app/start"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Stop an app instance. + * + * @param object $apiParams + * @access public + * @return object + */ + public function stopApp($apiParams) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/app/stop"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Create snippet. + * + * @param object $apiParams + * @access public + * @return object + */ + public function addSnippet($apiParams) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/snippet/add"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Update snippet. + * + * @param object $apiParams + * @access public + * @return object + */ + public function updateSnippet($apiParams) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/snippet/update"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Remove snippet + * + * @param object $apiParams + * @access public + * @return object + */ + public function removeSnippet($apiParams) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/snippet/remove"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Install app. + * + * @param object $apiParams + * @access public + * @return object + */ + public function installApp($apiParams) + { + //if(!empty($apiParams->settings)) $apiParams->settings = $this->transformSettings($apiParams->settings); + + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/app/install"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * uninstall an app instance. + * + * @param object $apiParams + * @access public + * @return object + */ + public function uninstallApp($apiParams) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/app/uninstall"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * Get app install logs. + * + * @param object $instance + * @access public + * @return object + */ + public function getAppLogs($instance) + { + $defaultSpace = $this->loadModel('space')->defaultSpace($this->app->user->account); + + $apiparams = new stdclass; + $apiparams->cluster = ''; + $apiparams->namespace = !empty($instance->spacedata->k8space) ? $instance->spacedata->k8space : $defaultSpace->k8space; + $apiparams->name = $instance->k8name; + $apiparams->tail = 500; + + $apiurl = "/api/cne/app/logs"; + return $this->apiget($apiurl, $apiparams, $this->config->CNE->api->headers); + } + + /** + * Validate SMTP settings. + * + * @param object $apiParams + * @access public + * @return bool + */ + public function validateSMTP($apiParams) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/system/smtp/validator"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return true; + + return false; + } + + /** + * Config app instance. + * + * @param object $apiParams + * @param object $settings + * @access public + * @return true + */ + public function configApp($apiParams, $settings) + { + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiParams->settings = $this->transformSettings($settings); + $apiUrl = "/api/cne/app/settings"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return true; + + return false; + } + + /** + * Transform setting format. + * + * @param array $settings + * @access private + * @return aray + */ + private function transformSettings($settings) + { + $transformedSettings = array(); + foreach($settings as $key => $value) + { + if(strpos($key, 'replicas') !== false && intval($value) < 1) $value = 1; // Replicas must be greater 0. + $transformedSettings[] = array('key' => str_replace('_', '.', $key), 'value' => $value); + } + return $transformedSettings; + } + + /** + * Get settings mapping by instance. + * + * @param object $instance + * @param object $mappings + * @access public + * @return object|null + */ + public function getSettingsMapping($instance, $mappings) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + $apiParams->mappings = $mappings; + + $apiUrl = "/api/cne/app/settings/mapping"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code != 200) return null; + + return $result->data; + } + + /** + * Get app config and resource. + * + * @param object $instance + * @access public + * @return bool|object + */ + public function getAppConfig($instance) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/app/settings/common"; + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code != 200) return false; + + $result->data->min = $result->data->oversold; + $result->data->max = $result->data->resources; + return $result->data; + } + + /** + * Get custom items of app. + * + * @param object $instance + * @access public + * @return bool|object + */ + public function getCustomItems($instance) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->name = $instance->k8name; + + if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/app/settings/custom"; + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code != 200) return false; + + return $result->data; + } + + /** + * Query status of an app instance. + * + * @param object $instance + * @access public + * @return object|null + */ + public function queryStatus($instance) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->name = $instance->k8name; + $apiParams->chart = $instance->chart; + $apiParams->namespace = $instance->spaceData->k8space; + $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + + $apiUrl = "/api/cne/app/status"; + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return $result; + + return $result; + } + + /** + * Query status of instance list. + * + * @param object $instanceList + * @access public + * @return object|null + */ + public function batchQueryStatus($instanceList) + { + $apiParams = new stdclass; + $apiParams->cluster = ''; + $apiParams->apps = array(); + + foreach($instanceList as $instance) + { + $app = new stdclass; + $app->name = $instance->k8name; + $app->chart = $instance->chart; + $app->namespace = $instance->spaceData->k8space; + $app->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; + + $apiParams->apps[] = $app; + } + + $apiUrl = "/api/cne/app/status/multi"; + $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + if(empty($result) || $result->code != 200) return array(); + + $statusList = array(); + foreach($result->data as $status) $statusList[$status->name] = $status; + + return $statusList; + } + + /** + * Get all database list of app. + * + * @param object $instance + * @access public + * @return object + */ + public function appDBList($instance) + { + $apiUrl = "/api/cne/app/dbs"; + $apiParams = array(); + $apiParams['cluster'] = ''; + $apiParams['name'] = $instance->k8name; + $apiParams['namespace'] = $instance->spaceData->k8space; + $apiParams['channel'] = $this->config->CNE->api->channel; + + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if(empty($result) || $result->code != 200 || empty($result->data)) return array(); + + $dbList = $result->data; + return array_combine(array_column($dbList, 'name'), $dbList); + } + + /** + * Get detail of app database. + * + * @param object $instance + * @param string $dbName + * @access public + * @return null|object + */ + public function appDBDetail($instance, $dbName) + { + $apiParams = array(); + $apiParams['cluster'] = ''; + $apiParams['name'] = $instance->k8name; + $apiParams['namespace'] = $instance->spaceData->k8space; + $apiParams['db'] = $dbName; + $apiParams['channel'] = $this->config->CNE->api->channel; + + $apiUrl = "/api/cne/app/dbs/detail"; + + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if(empty($result) || $result->code != 200 || empty($result->data)) return; + + return $result->data; + } + + /** + * Get database detail. + * + * @param string $dbService + * @param string $namespace + * @access public + * @return null|object + */ + public function dbDetail($dbService, $namespace) + { + $apiUrl = "/api/cne/component/dbservice/detail"; + $apiParams = array('name' => $dbService, 'namespace' => $namespace, 'channel' => $this->config->CNE->api->channel); + + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if(empty($result) || $result->code != 200 || empty($result->data)) return; + + return $result->data; + } + + /** + * Get all database list. + * + * @param string $namespace + * @param boolean $global true: global database + * @access public + * @return object + */ + public function allDBList($global = true, $namespace = 'default') + { + $apiUrl = "/api/cne/component/dbservice"; + $apiParams = array( 'global' => ($global ? 'true' : 'false'), 'namespace' => $namespace, 'channel' => $this->config->CNE->api->channel); + + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if(empty($result) || $result->code != 200 || empty($result->data)) return array(); + + $dbList = $result->data; + return array_combine(array_column($dbList, 'name'), $dbList); + } + + /** + * Get shared database list. + * + * @param string $dbType database type. + * @param string $namespace + * @access public + * @return array + */ + public function sharedDBList($dbType = 'mysql', $namespace = 'default') + { + $apiUrl = "/api/cne/component/gdb"; + $apiParams = array('kind' => $dbType, 'namespace' => $namespace, 'channel' => $this->config->CNE->api->channel); + + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if(empty($result) || $result->code != 200 || empty($result->data)) return array(); + + $dbList = $result->data; + return array_combine(array_column($dbList, 'name'), $dbList); + } + + /** + * Validate database name and user. + * + * @param string $dbService + * @param string $dbUser + * @param string $dbName + * @param string $namespace + * @access public + * @return object + */ + public function validateDB($dbService, $dbUser, $dbName, $namespace) + { + $apiParams = array(); + $apiParams['name'] = $dbService; + $apiParams['user'] = $dbUser; + $apiParams['database'] = $dbName; + $apiParams['namespace'] = $namespace; + + $apiUrl = "/api/cne/component/gdb/validation"; + $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + if($result && $result->code == 200) return $result->data->validation; + + $validation = new stdclass; + $validation->user = true; + $validation->database = true; + + return $validation; + } + + /** + * Get method of API. + * + * @param string $url + * @param array|object $data + * @param array $header example: array("key1:value1", "key2:value2") + * @param string $host + * @access public + * @return object + */ + public function apiGet($url, $data, $header = array(), $host = '') + { + $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url; + $requestUri .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($data, '', '&', PHP_QUERY_RFC3986); + $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'GET'), $header, 'json', 20)); + if($result && $result->code == 200) return $result; + if($result && $result->code != 200) return $this->translateError($result);; + + return $this->cneServerError(); + } + + /** + * Post method of API. + * + * @param string $url + * @param array|object $data + * @param array $header example: array("key1:value1", "key2:value2") + * @param string $host + * @access public + * @return object + */ + public function apiPost($url, $data, $header = array(), $host = '') + { + $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url; + $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'POST'), $header, 'json', 20)); + if($result && $result->code == 200) return $result; + if($result && $result->code != 200) return $this->translateError($result);; + + return $this->cneServerError(); + } + + /** + * Put method of API. + * + * @param string $url + * @param array|object $data + * @param array $header example: array("key1:value1", "key2:value2") + * @param string $host + * @access public + * @return object + */ + public function apiPut($url, $data, $header = array(), $host = '') + { + $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url; + $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'PUT'), $header, 'json', 20)); + if($result && $result->code == 200) return $result; + if($result && $result->code != 200) return $this->translateError($result);; + + return $this->cneServerError(); + } + + /** + * Delete method of API. + * + * @param string $url + * @param array|object $data + * @param array $header example: array("key1:value1", "key2:value2") + * @param string $host + * @access public + * @return object + */ + public function apiDelete($url, $data, $header = array(), $host = '') + { + $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url; + $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'DELETE'), $header, 'json', 20)); + if($result && $result->code == 200) return $result; + if($result && $result->code != 200) return $this->translateError($result);; + + return $this->cneServerError(); + } + + /** + * Return error object of api server. + * + * @access protected + * @return object + */ + protected function cneServerError() + { + $error = new stdclass; + $error->code = 600; + $error->message = $this->lang->CNE->serverError; + return $error; + } + + /** + * Get error + * + * @access public + * @return object + */ + public function getError() + { + return $this->error; + } + + /** + * Translate error message for multi language. + * + * @param object $apiResult + * @access protected + * @return void + */ + protected function translateError(&$apiResult) + { + $this->error->code = $apiResult->code; + $this->error->message = zget($this->lang->CNE->errorList, $apiResult->code, $this->lang->CNE->serverError); // Translate CNE api error message to multi language. + + $apiResult->message = $this->error->message; + + return $this->error; + } +} diff --git a/module/common/lang/common.php b/module/common/lang/common.php index bcaa9692dd..9340ebead9 100644 --- a/module/common/lang/common.php +++ b/module/common/lang/common.php @@ -97,6 +97,7 @@ $lang->contact = new stdclass(); $lang->dimension = new stdclass(); $lang->space = new stdclass(); $lang->store = new stdclass(); +$lang->CNE = new stdclass(); $lang->programstakeholder = new stdclass(); $lang->researchplan = new stdclass(); diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index d02f408e1d..4e2d33882e 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -715,6 +715,7 @@ $lang->navGroup->doctemplate = 'admin'; $lang->navGroup->notifysetting = 'admin'; $lang->navGroup->holidayseason = 'admin'; $lang->navGroup->measurement = 'admin'; +$lang->navGroup->system = 'admin'; $lang->navGroup->index = 'index'; $lang->navGroup->misc = 'misc'; diff --git a/module/common/model.php b/module/common/model.php index 016151f237..0e414726be 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -3773,6 +3773,81 @@ EOF; $error->message = $lang->error->httpServerError; return $error; } + + /** + * Print progress bar. + * + * @param int $percent percent 0-100 + * @param string $color color theme: gray, red, orange, green + * @param string $tip + * @param string $showValue possible values: '', 'percent', 'tip' + * @static + * @access public + * @return void + */ + public static function printProgressBar($percent, $color = '', $tip = '', $showValue = '') + { + if(empty($color) && $percent == 0) $color = 'gray'; + if(empty($color) && $percent > 0 && $percent < 60) $color = 'green'; + if(empty($color) && $percent >= 0 && $percent < 80) $color = 'orange'; + if(empty($color) && $percent >= 80) $color = 'red'; + + $title = $tip ? $tip : $percent . '%'; + $valueHtml = ''; + if($showValue == 'tip') $valueHtml = "
{$title}
"; + if($showValue == 'percent') $valueHtml = "
{$percent}%
"; + + echo << +
+
+ {$valueHtml} +
+ +EOT; + } + + /** + * Print progress pie. + * + * @param float $percent + * @param string $color HEX value of color + * @param string $tip + * @param string $tipPosition available values: left, right, top, bottom + * @static + * @access public + * @return void + */ + public static function printProgressPie($percent, $color = '', $tip = '', $tipPosition = 'bottom') + { + if(empty($color)) $color = self::getColorByLevel($percent); + + $title = $tip ? $tip : $percent . '%'; + + echo << +
{$percent}%
+ +EOT; + } + + /** + * Get color by level for percent that is in level range. + * + * @param float $percent + * @static + * @access public + * @return string HEX value of color + */ + public static function getColorByLevel($percent) + { + if($percent == 0) $color = '#999999'; // gray + if($percent > 0 and $percent < 60) $color = '#009e0f'; // green + if($percent >= 60 and $percent < 80) $color = '#ff9900'; // orange + if($percent >= 80) $color = '#cf2a27'; // red + + return $color; + } } class common extends commonModel diff --git a/module/instance/model.php b/module/instance/model.php index fd400b36eb..b55bc8d69e 100644 --- a/module/instance/model.php +++ b/module/instance/model.php @@ -33,8 +33,6 @@ class InstanceModel extends model */ public function getByID($id) { - $deadline = date('Y-m-d H:i:s', strtotime("-{$this->config->demoAppLife} minutes")); - $instance = $this->dao->select('*')->from(TABLE_INSTANCE) ->where('id')->eq($id) ->andWhere('deleted')->eq(0) @@ -60,8 +58,6 @@ class InstanceModel extends model */ public function getByIdList($idList) { - $deadline = date('Y-m-d H:i:s', strtotime("-{$this->config->demoAppLife} minutes")); - $instances = $this->dao->select('*')->from(TABLE_INSTANCE) ->where('id')->in($idList) ->andWhere('deleted')->eq(0) @@ -107,8 +103,6 @@ class InstanceModel extends model */ public function getByAccount($account = '', $pager = null, $pinned = '', $searchParam = '', $status = 'all') { - $deadline = date('Y-m-d H:i:s', strtotime("-{$this->config->demoAppLife} minutes")); - $defaultSpace = $this->loadModel('space')->defaultSpace($account ? $account : $this->app->user->account); $instances = $this->dao->select('instance.*')->from(TABLE_INSTANCE)->alias('instance') @@ -189,8 +183,6 @@ class InstanceModel extends model */ public function totalServices() { - $deadline = date('Y-m-d H:i:s', strtotime("-{$this->config->demoAppLife} minutes")); - $defaultSpace = $this->loadModel('space')->defaultSpace($this->app->user->account); $count = $this->dao->select('count(*) as qty')->from(TABLE_INSTANCE)->alias('instance') @@ -1411,14 +1403,6 @@ class InstanceModel extends model { if($backup->creator != 'auto') continue; // Only delete data madde by auto backup. if($latestBackup && $latestBackup->name == $backup->name) continue; // Keep latest successful backup. - - $deadline = intval($backup->create_time) + $instance->backupKeepDays * 24 * 3600; - //$deadline = intval($backup->create_time) + 300; // Debug codes: delete backup if it's life is older 5 minuts. - if($deadline < time()) - { - $this->deleteBackup($instance, $backup->name); - $this->action->create('instance', $instance->id, 'deleteExpiredBackup', '', json_encode(array('data' => $backup))); - } } } } @@ -1658,12 +1642,10 @@ class InstanceModel extends model */ public function deleteExpiredDemoInstance() { - $deadline = date('Y-m-d H:i:s', strtotime("-{$this->config->demoAppLife} minutes")); $demoAccounts = array_filter(explode(',', $this->config->demoAccounts)); $instanceList = $this->dao->select('*')->from(TABLE_INSTANCE) ->where('deleted')->eq(0) - ->andWhere('createdAt')->lt($deadline) ->andWhere('createdBy')->in($demoAccounts) ->fetchAll(); if(empty($instanceList)) return; diff --git a/module/system/control.php b/module/system/control.php new file mode 100644 index 0000000000..9cbfe71134 --- /dev/null +++ b/module/system/control.php @@ -0,0 +1,639 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +class system extends control +{ + /** + * System index. + * + * @access public + * @return void + */ + public function index() + { + $this->view->title = $this->lang->system->common; + + $this->display(); + } + + /** + * Dashboard page. + * + * @param int $total + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function dashboard($total = 0, $recPerPage = 20, $pageID = 1) + { + $this->loadModel('cne'); + $this->app->loadClass('pager', true); + $pager = new pager($total, $recPerPage, $pageID); + + $instances = $this->loadModel('instance')->getByAccount($this->app->user->account, $pager, '', '', 'running'); + + $actions = $this->loadModel('action')->getDynamic('all', 'today'); + + $this->view->position[] = $this->lang->my->common; + + $this->view->title = $this->lang->my->common; + $this->view->instances = $instances; + $this->view->actions = $actions; + $this->view->cneMetrics = $this->cne->cneMetrics(); + $this->view->instancesMetrics = $this->cne->instancesMetrics($instances); + $this->view->pager = $pager; + + $this->display(); + } + + /** + * Show database list. + * + * @access public + * @return void + */ + public function dbList() + { + $this->app->loadLang('instance'); + + $this->view->title = $this->lang->system->dbManagement; + $this->view->dbList = $this->loadModel('cne')->allDBList(); + + $this->display(); + } + + /** + * Test the connection of LDAP by post parameters. + * + * @access public + * @return void + */ + public function testLDAPConnection() + { + $settings = fixer::input('post') + ->setDefault('host', '') + ->setDefault('port', '') + ->setDefault('bindDN', '') + ->setDefault('bindPass', '') + ->setDefault('baseDN', '') + ->get(); + + $success = $this->system->testLDAPConnection($settings); + if($success) return $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->verifyLDAPSuccess)); + + return $this->send(array('result' => 'fail', 'message' => $this->lang->system->errors->verifyLDAPFailed)); + } + + /** + * Install LDAP + * + * @access public + * @return void + */ + public function installLDAP() + { + if($this->system->hasSystemLDAP()) return print(js::locate($this->inLink('ldapView'))); + + $channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel; + $ldapApp = $this->loadModel('store')->getAppInfoByChart('openldap', $channel, false); + if($_POST) + { + $postData = fixer::input('post')->setDefault('source', 'qucheng')->get(); + if($postData->source == 'qucheng') + { + $this->system->installQuchengLDAP($ldapApp, $channel); + } + else if($postData->source == 'extra') + { + $this->system->configExtraLDAP((object)$postData->extra); + } + else + { + dao::$errors[] = $this->lang->system->notSupportedLDAP; + } + + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->ldapInstallSuccess, 'locate' => $this->inLink('ldapView'))); + } + + $this->lang->switcherMenu = $this->system->getLDAPSwitcher(); + + $this->view->title = $this->lang->system->ldapManagement; + $this->view->ldapApp = $ldapApp; + $this->view->activeLDAP = $this->system->getActiveLDAP(); + $this->view->ldapSettings = $this->system->getExtraLDAPSettings(); + + $this->display(); + } + + /** + * Edit extra LDAP. + * + * @access public + * @return void + */ + public function editLDAP() + { + $channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel; + $ldapApp = $this->loadModel('store')->getAppInfoByChart('openldap', $channel, false); + if($_POST) + { + session_write_close(); + $this->system->updateLDAP($ldapApp, $channel); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->ldapUpdateSuccess, 'locate' => $this->inLink('ldapView'))); + } + + $this->view->title = $this->lang->system->editLDAP; + + + $this->view->ldapApp = $ldapApp; + $this->view->activeLDAP = $this->system->getActiveLDAP(); + $this->view->ldapSettings = $this->system->getExtraLDAPSettings(); + $this->display(); + } + + /** + * ajaxUpdatingLDAPProgress + * + * @access public + * @return void + */ + public function ajaxUpdatingLDAPProgress() + { + session_write_close(); + + $number = $this->loadModel('setting')->getItem('owner=system&module=common§ion=ldap&key=updatingProgress'); + echo sprintf($this->lang->system->LDAP->updatingProgress, intval($number)); + } + + /** + * LDAP view. + * + * @access public + * @return void + */ + public function ldapView() + { + $this->loadModel('instance'); + $this->app->loadLang('instance'); + + $ldapInstance = new stdclass; + $ldapInstance->id = 0; + + $activeLDAP = $this->loadModel('setting')->getItem('owner=system&module=common§ion=ldap&key=active'); + if($activeLDAP == 'qucheng') + { + $instanceID = $this->loadModel('setting')->getItem('owner=system&module=common§ion=ldap&key=instanceID'); + $ldapInstance = $this->instance->getByID($instanceID); + if(empty($ldapInstance)) return print js::alert($this->lang->system->notices->noLDAP); + + $ldapInstance = $this->instance->freshStatus($ldapInstance); + $ldapSettings = json_decode($ldapInstance->ldapSettings); + } + else if($activeLDAP == 'extra') + { + $ldapSettings = $this->system->getExtraLDAPSettings(); + } + else + { + return print js::alert($this->lang->system->notices->noLDAP); + } + + $this->lang->switcherMenu = $this->system->getLDAPSwitcher(); + + $this->view->title = $this->lang->system->ldapManagement; + + $this->view->activeLDAP = $activeLDAP; + $this->view->instanceID = $ldapInstance->id; + $this->view->ldapInstance = $ldapInstance; + $this->view->ldapSettings = $ldapSettings; + + $this->display(); + } + + /** + * Uninstall all LDAP in system. (This function is only for debug and test.) + * + * @access public + * @return void + */ + public function uninstallLDAP() + { + if(!$this->config->debug) return; // Only run in debug mode. + + /* 1. uninstall QuCheng LDAP. */ + if($this->system->uninstallQuChengLDAP()) + { + echo date('Y-m-d H:i:s') . ": Uninstall QuCheng LDAP success.
"; + } + else + { + echo date('Y-m-d H:i:s') . ": Uninstall QuCheng LDAP fail.
"; + $errors = dao::getError(); + foreach($errors as $error) echo $error . '
'; + } + + /* 2. uninstall extra LDAP. */ + if($this->system->uninstallExtraLDAP()) + { + echo date('Y-m-d H:i:s') . ": Uninstall extra LDAP success.
"; + } + else{ + echo date('Y-m-d H:i:s') . ": Uninstall extra LDAP fail.
"; + $errors = dao::getError(); + foreach($errors as $error) echo $error . '
'; + } + } + + /** + * OSS view. + * + * @access public + * @return void + */ + public function ossView() + { + $this->loadModel('cne'); + + $minioInstance = new stdclass; + $minioInstance->k8name = 'cne-operator'; + $minioInstance->spaceData = new stdclass; + $minioInstance->spaceData->k8space = $this->config->k8space; + + $ossAccount = $this->cne->getDefaultAccount($minioInstance, '', 'minio'); + $ossDomain = $this->cne->getDomain($minioInstance, '', 'minio'); + $this->lang->switcherMenu = $this->system->getOssSwitcher(); + + $this->view->title = $this->lang->system->oss->common; + $this->view->ossAccount = $ossAccount; + $this->view->ossDomain = $ossDomain; + + $this->display(); + } + + /** + * Install SMTP. + * + * @access public + * @return void + */ + public function installSMTP() + { + if($this->system->smtpSnippetName()) return print(js::locate($this->inLink('smtpView'))); + + if($_POST) + { + $channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel; + $this->system->installSysSMTP($channel); + + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->smtpInstallSuccess, 'locate' => $this->inLink('smtpView'))); + } + + $this->lang->switcherMenu = $this->system->getSMTPSwitcher(); + + $this->view->title = $this->lang->system->SMTP->common; + $this->view->smtpSettings = $this->system->getSMTPSettings(); + $this->view->smtpLinked = false; + $this->view->activeSMTP = false; + + $this->display(); + } + + /** + * Edit SMTP. + * + * @access public + * @return void + */ + public function editSMTP() + { + $this->loadModel('instance'); + $this->app->loadLang('instance'); + + if($_POST) + { + $channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel; + $postData = fixer::input('post')->setDefault('source', 'qucheng')->get(); + $this->system->updateSMTPSettings(); + + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->smtpUpdateSuccess, 'locate' => $this->inLink('smtpView'))); + } + + $this->lang->switcherMenu = $this->system->getSMTPSwitcher(); + + $this->view->title = $this->lang->system->SMTP->editSMTP; + $this->view->smtpSettings = $this->system->getSMTPSettings(); + $this->view->smtpLinked = $this->instance->countSMTP(); + $this->view->activeSMTP = zget($this->view->smtpSettings, 'enabled', false); + + $this->display(); + } + + /** + * Show SMTP setting detail. + * + * @access public + * @return void + */ + public function smtpView() + { + $this->loadModel('instance'); + $this->app->loadLang('instance'); + + $instanceID = $this->loadModel('setting')->getItem('owner=system&module=common§ion=smtp&key=instanceID'); + $smtpInstance = $this->instance->getByID($instanceID); + if(empty($smtpInstance)) return print js::alert($this->lang->system->notices->notFoundSMTPService); + + + $this->lang->switcherMenu = $this->system->getSMTPSwitcher(); + + $this->view->title = $this->lang->system->SMTP->common; + $this->view->smtpSettings = $this->system->getSMTPSettings(); + $this->view->smtpInstance = $smtpInstance; + + $this->display(); + } + + /** + * Uninstall SMTP. (This function is only for debug and test.) + * + * @access public + * @return void + */ + public function uninstallSMTP() + { + if(!$this->config->debug) return; // Only run in debug mode. + + /* Uninstall system SMTP proxy APP. */ + if($this->system->uninstallSysSMTP()) + { + echo date('Y-m-d H:i:s') . ": Uninstall system SMTP success.
"; + } + else + { + echo date('Y-m-d H:i:s') . ": Uninstall system SMTP fail.
"; + $errors = dao::getError(); + foreach($errors as $error) echo $error . '
'; + } + } + + /** + * Config customer's domain. + * + * @access public + * @return void + */ + public function configDomain() + { + $domainSettings = $this->system->getDomainSettings(); + if($domainSettings->customDomain) return print(js::locate($this->inLink('domainView'))); + + return print(js::locate($this->inLink('editDomain'))); + } + + /** + * Edit customer's domain. + * + * @access public + * @return void + */ + public function editDomain() + { + $this->loadModel('instance'); + + if($_POST) + { + session_write_close(); + $this->system->saveDomainSettings(); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::$errors)); + + return $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->updateDomainSuccess, 'locate' => $this->inlink('domainView'))); + } + + $this->view->title = $this->lang->system->domain->common; + $this->view->domainSettings = $this->system->getDomainSettings(); + + $this->display(); + } + + /** + * AjaxValidCert + * + * @access public + * @return void + */ + public function ajaxValidateCert() + { + $certData = fixer::input('post')->get(); + + $this->dao->select('*')->from('system')->data($certData) + ->batchCheck('customDomain,certPem,certKey', 'notempty'); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::$errors)); + + if(!validater::checkREG($certData->customDomain, '/^((?!-)[a-z0-9-]{1,63}(?send(array('result' => 'fail', 'message' => $this->lang->system->errors->invalidDomain)); + } + + $certName = 'tls-' . str_replace('.', '-',$certData->customDomain); + $result = $this->loadModel('cne')->validateCert($certName, $certData->certPem, $certData->certKey, $certData->customDomain); + if($result->code == 200) return $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->validCert)); + + return $this->send(array('result' => 'fail', 'message' => $result->message)); + } + + /** + * Show progress of updating domains. + * + * @access public + * @return void + */ + public function ajaxUpdatingDomainProgress() + { + session_write_close(); + + $oldDomainQty = $this->loadModel('instance')->countOldDomain(); + return print(sprintf($this->lang->system->domain->updatingProgress, $oldDomainQty)); + } + + /** + * Domain settings view. + * + * @access public + * @return void + */ + public function domainView() + { + $domainSettings = $this->system->getDomainSettings(); + $certName = 'tls-' . str_replace('.', '-', $domainSettings->customDomain); + $cert = $this->loadModel('cne')->certInfo($certName); + + $notAfter = zget($cert, 'not_after', ''); + if($notAfter) $cert->expiredDate = date('Y-m-d H:i:s', $notAfter); + + $this->view->title = $this->lang->system->domain->common; + $this->view->domainSettings = $domainSettings; + $this->view->cert = $cert; + + $this->display(); + } + + /** + * Config Server Load Balancing. + * + * @access public + * @return void + */ + public function configSLB() + { + $slbSettings = $this->system->getSLBSettings(); + if($slbSettings->name) return print(js::locate($this->inLink('slbView'))); + + return print(js::locate($this->inLink('editSLB'))); + } + + /** + * Edit SLB. + * + * @access public + * @return void + */ + public function editSLB() + { + if($_POST) + { + $this->system->saveSLBSettings(); + if(dao::isError()) + { + return $this->send(array('result' => 'fail', 'message' => dao::getError())); + } + + return $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->configSLBSuccess, 'locate' => $this->inLink('SLBView'))); + } + + $this->view->title = $this->lang->system->SLB->common; + $this->view->SLBSettings = $this->system->getSLBSettings(); + + $this->display(); + } + + /** + * SLB View. + * + * @access public + * @return void + */ + public function SLBView() + { + $this->view->title = $this->lang->system->SLB->common; + $this->view->slbSettings = $this->system->getSLBSettings(); + + $this->display(); + } + + /** + * Verify SMTP account by ajax. + * + * @access public + * @return void + */ + public function ajaxVerifySMTPAccount() + { + $accountInfo= fixer::input('post')->get(); + + $passed = $this->loadModel('cne')->validateSMTP($accountInfo); + if($passed) $this->send(array('result' => 'success', 'message' => $this->lang->system->notices->verifySMTPSuccess)); + + $this->send(array('result' => 'fail', 'message' => $this->lang->system->errors->verifySMTPFailed)); + } + + /** + * Generate database auth parameters and jump to login page. + * + * @access public + * @return void + */ + public function ajaxDBAuthUrl() + { + $post = fixer::input('post') + ->setDefault('namespace', 'default') + ->get(); + if(empty($post->dbName)) return $this->send(array('result' => 'fail', 'message' => $this->lang->system->errors->dbNameIsEmpty)); + + $detail = $this->loadModel('cne')->dbDetail($post->dbName, $post->namespace); + if(empty($detail)) return $this->send(array('result' => 'fail', 'message' => $this->lang->system->errors->notFoundDB)); + + $this->app->loadConfig('instance'); + $dbAuth = array(); + $dbAuth['driver'] = zget($this->config->instance->adminer->dbTypes, $post->dbType, ''); + $dbAuth['server'] = $detail->host . ':' . $detail->port; + $dbAuth['username'] = $detail->username; + $dbAuth['db'] = $detail->database; + $dbAuth['password'] = $detail->password; + + $url = '/adminer?'. http_build_query($dbAuth); + $this->send(array('result' => 'success', 'message' => '', 'data' => array('url' => $url))); + } + + /** + * Get LDAP info by ajax. + * + * @access public + * @return void + */ + public function ajaxLdapInfo() + { + $instanceID = $this->loadModel('setting')->getItem('owner=system&module=common§ion=ldap&key=instanceID'); + $ldapInstance = $this->loadModel('instance')->getByID($instanceID); + if(empty($ldapInstance)) return $this->send(array('result' => 'fail', 'message' => $this->lang->system->errors->notFoundLDAP)); + + $ldapSetting = json_decode($ldapInstance->ldapSettings); + + $secretKey = helper::readKey(); + $password = openssl_decrypt($ldapSetting->auth->password, 'DES-ECB', $secretKey); + if(!$password) $password = openssl_decrypt($ldapSetting->auth->password, 'DES-ECB', $ldapInstance->createdAt); // Secret key was createdAt field value less v2.2. + + $this->send(array('result' => 'success', 'message' => '', 'data' => array('domain' => $this->instance->url($ldapInstance), 'account' => $ldapSetting->auth->username, 'pass' => $password))); + } + + /** + * Get oss account and domain by ajax. + * + * @access public + * @return void + */ + public function ajaxOssInfo() + { + $minioInstance = new stdclass; + $minioInstance->k8name = 'cne-operator'; + $minioInstance->spaceData = new stdclass; + $minioInstance->spaceData->k8space = $this->config->k8space; + + $ossAccount = $this->loadModel('cne')->getDefaultAccount($minioInstance, '', 'minio'); + + $ossDomain = $this->cne->getDomain($minioInstance, '', 'minio'); + $ossDomain->domain = $ossDomain->access_host; + + $url = $this->loadModel('instance')->url($ossDomain); + + if($ossAccount and $ossAccount) return $this->send(array('result' => 'success', 'message' => '', 'data' => array('account' => $ossAccount, 'url' => $url))); + + $this->send(array('result' => 'fail', 'message' => $this->lang->system->errors->failGetOssAccount)); + } +} diff --git a/module/system/css/dblist.css b/module/system/css/dblist.css new file mode 100644 index 0000000000..f6f3b660e3 --- /dev/null +++ b/module/system/css/dblist.css @@ -0,0 +1,3 @@ +#mainContent .table {margin: auto;width: 60%; min-width:400px; max-width: 800px;} +#mainContent .main-header {margin-bottom: 20px;} +#mainContent .main-header h2{font-size: 18px;} diff --git a/module/system/css/editdomain.css b/module/system/css/editdomain.css new file mode 100644 index 0000000000..1f7c85f630 --- /dev/null +++ b/module/system/css/editdomain.css @@ -0,0 +1 @@ +table tr th.new-domain-label{vertical-align: top; padding-top: 14px;} diff --git a/module/system/css/editldap.css b/module/system/css/editldap.css new file mode 100644 index 0000000000..d1fa0d1d8b --- /dev/null +++ b/module/system/css/editldap.css @@ -0,0 +1 @@ +.advanced {padding:5px 0 5px 150px;} diff --git a/module/system/css/index.css b/module/system/css/index.css new file mode 100644 index 0000000000..bb3b7523c8 --- /dev/null +++ b/module/system/css/index.css @@ -0,0 +1,7 @@ +.plug-container > div{margin-bottom: 20px;} +.plug-container a {display: inline-block; width: 150px;} +.plug-container a:hover { text-decoration: none; box-shadow: 0 1px 5px rgb(0 0 0 / 18%);} +.logo { display: inline-block; padding: 10px;} +.logo .icon {font-size: 100px; color: #70c0fb;} +.logo img {width: 100px; height:100px;} +.plug-title {display: inline-block; padding-top: 10px; text-align: center; font-size: 16px; font-weight: 500;} diff --git a/module/system/css/installldap.css b/module/system/css/installldap.css new file mode 100644 index 0000000000..d1fa0d1d8b --- /dev/null +++ b/module/system/css/installldap.css @@ -0,0 +1 @@ +.advanced {padding:5px 0 5px 150px;} diff --git a/module/system/css/installsmtp.css b/module/system/css/installsmtp.css new file mode 100644 index 0000000000..dde26ea91f --- /dev/null +++ b/module/system/css/installsmtp.css @@ -0,0 +1 @@ +#mainContent .main-col {display: block;} diff --git a/module/system/css/ldapview.css b/module/system/css/ldapview.css new file mode 100644 index 0000000000..b449e569c2 --- /dev/null +++ b/module/system/css/ldapview.css @@ -0,0 +1,7 @@ +.btn.label-lg.label-primary.btn-edit {color: #61be68;} +.btn.label-lg.label-outline {background-color: #ffffff!important;} +.btn.label-lg.label-outline:hover, .btn-visit.btn:focus {background-color: #e5fbf3!important;} +.edit-tools-tips {display: inline-block; margin: 0 10px;} +#ldapAccountModal .modal-content {padding-bottom: 20px;} +input#ldapPassword {border:none;} +#ldapPassBtn {border:none;} diff --git a/module/system/css/ossview.css b/module/system/css/ossview.css new file mode 100644 index 0000000000..5c80d0a5d5 --- /dev/null +++ b/module/system/css/ossview.css @@ -0,0 +1,5 @@ +.btn.label-lg.label-outline {background-color: #ffffff!important;} +.btn.label-lg.label-outline:hover, .btn-visit.btn:focus {background-color: #e5fbf3!important;} +input#ossPassword {border:none;} +input#ossSK{border:none;} + diff --git a/module/system/css/smtpview.css b/module/system/css/smtpview.css new file mode 100644 index 0000000000..899c01945b --- /dev/null +++ b/module/system/css/smtpview.css @@ -0,0 +1 @@ +#smtpPassBtn{border: 0;} diff --git a/module/system/js/dblist.js b/module/system/js/dblist.js new file mode 100644 index 0000000000..3b5f658b31 --- /dev/null +++ b/module/system/js/dblist.js @@ -0,0 +1,22 @@ +$(function() +{ + $('button.db-login').on('click', function(event) + { + var dbName = $(event.target).data('db-name'); + var dbType = $(event.target).data('db-type'); + var namespace = $(event.target).data('namespace'); + + $.post(createLink('system', 'ajaxDBAuthUrl'), {dbName, namespace, dbType}).done(function(res) + { + var response = JSON.parse(res); + if(response.result == 'success') + { + window.parent.open(response.data.url, 'Adminer'); + } + else + { + bootbox.alert(response.message); + } + }); + }); +}); diff --git a/module/system/js/editdomain.js b/module/system/js/editdomain.js new file mode 100644 index 0000000000..39651e41bc --- /dev/null +++ b/module/system/js/editdomain.js @@ -0,0 +1,143 @@ +$(function() +{ + /** + * Fresh submitBtn status. + * + * @access public + * @return void + */ + function freshSubmitBtn() + { + if($('#httpstrue:checked').length == 0) + { + $('#submitBtn').attr('disabled', false); + return; + } + var pass = $('#validateCertBtn').attr('pass') == 'true'; + if(pass) + { + $('#submitBtn').attr('disabled', false); + } + else + { + $('#submitBtn').attr('disabled', true); + } + } + + freshSubmitBtn(); + + /** + * Toggle certificate textarea. + * + * @access public + * @return void + */ + function toggleCertBox() + { + $showCert = $("#httpstrue[type=checkbox]:checked").length > 0; + if($showCert) + { + $('#cert-box').show(); + } + else + { + $('#cert-box').hide(); + } + + freshSubmitBtn(); + } + + toggleCertBox(); + + $("#httpstrue[type=checkbox]").on('change', function() + { + toggleCertBox(); + }); + + $('#validateCertBtn').on('click', function() + { + var certData = {}; + certData.customDomain = $('#customDomain').val(); + certData.certPem = $('#certPem').val(); + certData.certKey = $('#certKey').val(); + $.post(createLink('system', 'ajaxValidateCert'), certData).done(function(response) + { + var res = JSON.parse(response); + if(res.result == 'success') + { + $('#validateCertBtn').attr('pass', 'true'); + $('#validateMsg').removeClass('text-red').addClass('text-green'); + $('#validateMsg').html(res.message); + } + else + { + $('#validateCertBtn').attr('pass', 'false'); + $('#validateMsg').removeClass('text-green').addClass('text-red'); + var errMessage = res.message; + if(res.message instanceof Array) errMessage = res.message.join(' '); + if(res.message instanceof Object) errMessage = Object.values(res.message).join(' '); + + $('#validateMsg').html(errMessage); + } + freshSubmitBtn(); + }); + }); + + var timerID = 0; + + /** + * Show progress modal and fresh progress of updating domain by ajax. + * + * @access public + * @return void + */ + function showProgressModal() + { + $('#waiting').modal('show'); + timerID = setInterval(function() + { + $.get(createLink('system', 'ajaxUpdatingDomainProgress'), function(data) + { + $('#waiting #message').html(data); + }); + }, 1000); + }; + + $('#submitBtn').on('click', function() + { + bootbox.confirm(notices.confirmUpdateDomain, function(result) + { + if(!result) return; + + showProgressModal(); + $('#submitBtn').attr('disabled', true); + + var domainData = $('#domainForm').serializeArray(); + $.post(createLink('system', 'editDomain'), domainData).done(function(response) + { + $('#submitBtn').attr('disabled', false); + + var res = JSON.parse(response); + if(res.result == 'success') + { + parent.window.location.href = res.locate; + } + else + { + $('#waiting').modal('hide'); + clearInterval(timerID); + + var errMessage = res.message; + if(res.message instanceof Array) errMessage = res.message.join('
'); + if(res.message instanceof Object) errMessage = Object.values(res.message).join('
'); + + bootbox.alert( + { + title: notices.fail, + message: errMessage, + }); + } + }); + }); + }); +}); diff --git a/module/system/js/editldap.js b/module/system/js/editldap.js new file mode 100644 index 0000000000..583bd742b6 --- /dev/null +++ b/module/system/js/editldap.js @@ -0,0 +1,155 @@ +$(function() +{ + /** + * Fresh submit button. + * + * @access public + * @return void + */ + function freshSubmitBtn() + { + var enableLDAP = $('#LDAPForm input[type=checkbox]:checked').length > 0; + var ldapCheckPass = true; + if($('#LDAPForm select[name=source]').val() == 'extra') + { + ldapCheckPass = $('#testConnectBtn').attr('pass') == 'true'; + } + + if(enableLDAP && ldapCheckPass) + { + $('#LDAPForm #submitBtn').attr('disabled', false); + } + else + { + $('#LDAPForm #submitBtn').attr('disabled', true); + } + } + + freshSubmitBtn(); + + $('#LDAPForm input[type=checkbox]').on('change', function(event) + { + freshSubmitBtn(); + }); + + $('#LDAPForm input[type=checkbox]').change(); + + $('select[name=source]').on('change', function(event) + { + if($(event.target).val() == 'qucheng') + { + $('#quchengLDAP').show(); + $('#extraLDAP').hide(); + } + else + { + $('#quchengLDAP').hide(); + $('#extraLDAP').show(); + } + + freshSubmitBtn(); + }); + $('select[name=source]').change(); + + $('#testConnectBtn').on('click', function(event) + { + var settings = {}; + settings.host = $('input[name="extra[host]"]').val(); + settings.port = $('input[name="extra[port]"]').val(); + settings.bindDN = $('input[name="extra[bindDN]"]').val(); + settings.bindPass = $('input[name="extra[bindPass]"]').val(); + settings.baseDN = $('input[name="extra[baseDN]"]').val(); + if(!settings.host || !settings.port || !settings.bindDN || !settings.bindPass || !settings.baseDN) + { + bootbox.alert( + { + title: notices.attention, + message: notices.fillAllRequiredFields, + }); + return; + } + + $.post(createLink('system', 'testLDAPConnection'), settings).done(function(response) + { + try + { + var res = JSON.parse(response); + } + catch(error) + { + var res = {result: 'fail', message: errors.verifyLDAPFailed,}; + } + $('#connectResult').html(res.message); + if(res.result == 'success') + { + $('#testConnectBtn').attr('pass', 'true'); + $('#connectResult').removeClass('text-red').addClass('text-success'); + freshSubmitBtn(); + } + else + { + $('#testConnectBtn').attr('pass', 'false'); + $('#connectResult').removeClass('text-success').addClass('text-red'); + freshSubmitBtn(); + } + }); + }); + + var timerID = 0; + + /** + * Show updating LDAP progress modal. + * + * @access public + * @return void + */ + function showProgressModal() + { + $('#waiting').modal('show'); + timerID = setInterval(function() + { + $.get(createLink('system', 'ajaxUpdatingLDAPProgress'), function(data) + { + $('#waiting #message').html(data); + }); + }, 1000); + }; + + $('#submitBtn').on('click', function() + { + bootbox.confirm(notices.confirmUpdateLDAP, function(result) + { + if(!result) return; + + showProgressModal(); + $('#submitBtn').attr('disabled', true); + + var ldapData = $('#LDAPForm').serializeArray(); + $.post(createLink('system', 'editLDAP'), ldapData).done(function(response) + { + $('#submitBtn').attr('disabled', false); + + var res = JSON.parse(response); + if(res.result == 'success') + { + parent.window.location.href = res.locate; + } + else + { + $('#waiting').modal('hide'); + clearInterval(timerID); + + var errMessage = res.message; + if(res.message instanceof Array) errMessage = res.message.join('
'); + if(res.message instanceof Object) errMessage = Object.values(res.message).join('
'); + + bootbox.alert( + { + title: notices.fail, + message: errMessage, + }); + } + }); + }); + }); +}); diff --git a/module/system/js/editslb.js b/module/system/js/editslb.js new file mode 100644 index 0000000000..c1e98ad428 --- /dev/null +++ b/module/system/js/editslb.js @@ -0,0 +1,34 @@ +$(function() +{ + var overtime = 30; + var timerID = 0; + $("#submitBtn").on('click', function() + { + $('#waiting').modal('show'); + timerID = setInterval(function() + { + $('#timer').text(overtime); + overtime--; + }, 1000); + + var slbData = {}; + slbData.ippool = $('#ippool').val(); + $.post(createLink('system', 'editSLB'), slbData).done(function(response) + { + $('#waiting').modal('hide'); + clearInterval(timerID); + overtime = 30; + + var res = JSON.parse(response); + if(res.result == 'success'){ + parent.window.location.href = res.locate; + }else{ + bootbox.alert( + { + title: notices.fail, + message: res.message, + }); + } + }); + }); +}); diff --git a/module/system/js/editsmtp.js b/module/system/js/editsmtp.js new file mode 100644 index 0000000000..664f09ff5a --- /dev/null +++ b/module/system/js/editsmtp.js @@ -0,0 +1,73 @@ +$(function() +{ + /** + * Fresh submit btton by enable SMTP checkboc value and verified result of SMTP account. + * + * @access public + * @return void + */ + function freshSubmitBtn() + { + var enableSMTP = $('#smtpForm input[type=checkbox]:checked').length > 0; + var accountRight = $('#verifyAccountBtn').attr('pass') == 'true'; + + if(enableSMTP && accountRight) + { + $('#smtpForm button[type=submit]').attr('disabled', false); + } + else + { + $('#smtpForm button[type=submit]').attr('disabled', true); + } + } + + $('#smtpForm input[type=checkbox]').on('change', function(event) + { + freshSubmitBtn(); + }); + + $('#smtpForm input[type=checkbox]').change(); + + $('#verifyAccountBtn').on('click', function(event) + { + var settings = {}; + settings.host = $("input[name='host']").val(); + settings.port = $("input[name='port']").val(); + settings.user = $("input[name='user']").val(); + settings.pass = $("input[name='pass']").val(); + if(!settings.host || !settings.port || !settings.user || !settings.pass) + { + bootbox.alert( + { + title: notices.attention, + message: notices.fillAllRequiredFields, + }); + return; + } + + $.post(createLink('system', 'ajaxVerifySMTPAccount'), settings).done(function(response) + { + try + { + var res = JSON.parse(response); + } + catch(error) + { + var res = {result: 'fail', message: errors.verifySMTPFailed,}; + } + $('#verifyResult').html(res.message); + if(res.result == 'success') + { + $('#verifyAccountBtn').attr('pass', 'true'); + $('#verifyResult').removeClass('text-red').addClass('text-success'); + freshSubmitBtn(); + } + else + { + $('#verifyAccountBtn').attr('pass', 'false'); + $('#verifyResult').removeClass('text-success').addClass('text-red'); + freshSubmitBtn(); + } + }); + }); +}); diff --git a/module/system/js/installldap.js b/module/system/js/installldap.js new file mode 100644 index 0000000000..fe5297b8e1 --- /dev/null +++ b/module/system/js/installldap.js @@ -0,0 +1,129 @@ +$(function() +{ + /** + * Fresh submit button. + * + * @access public + * @return void + */ + function freshSubmitBtn() + { + var enableLDAP = $('#LDAPForm input[type=checkbox]:checked').length > 0; + var ldapCheckPass = true; + if($('#LDAPForm select[name=source]').val() == 'extra') + { + ldapCheckPass = $('#testConnectBtn').attr('pass') == 'true'; + } + + if(enableLDAP && ldapCheckPass) + { + $('#LDAPForm #submitBtn').attr('disabled', false); + } + else + { + $('#LDAPForm #submitBtn').attr('disabled', true); + } + } + + freshSubmitBtn(); + + $('#LDAPForm input[type=checkbox]').on('change', function(event) + { + freshSubmitBtn(); + }); + + $('#LDAPForm input[type=checkbox]').change(); + + $('select[name=source]').on('change', function(event) + { + if($(event.target).val() == 'qucheng') + { + $('#quchengLDAP').show(); + $('#extraLDAP').hide(); + } + else + { + $('#quchengLDAP').hide(); + $('#extraLDAP').show(); + } + + freshSubmitBtn(); + }); + $('select[name=source]').change(); + + $('#testConnectBtn').on('click', function(event) + { + var settings = {}; + settings.host = $('input[name="extra[host]"]').val(); + settings.port = $('input[name="extra[port]"]').val(); + settings.bindDN = $('input[name="extra[bindDN]"]').val(); + settings.bindPass = $('input[name="extra[bindPass]"]').val(); + settings.baseDN = $('input[name="extra[baseDN]"]').val(); + if(!settings.host || !settings.port || !settings.bindDN || !settings.bindPass || !settings.baseDN) + { + bootbox.alert( + { + title: notices.attention, + message: notices.fillAllRequiredFields, + }); + return; + } + + $.post(createLink('system', 'testLDAPConnection'), settings).done(function(response) + { + try + { + var res = JSON.parse(response); + } + catch(error) + { + var res = {result: 'fail', message: errors.verifyLDAPFailed,}; + } + $('#connectResult').html(res.message); + if(res.result == 'success') + { + $('#testConnectBtn').attr('pass', 'true'); + $('#connectResult').removeClass('text-red').addClass('text-success'); + freshSubmitBtn(); + } + else + { + $('#testConnectBtn').attr('pass', 'false'); + $('#connectResult').removeClass('text-success').addClass('text-red'); + freshSubmitBtn(); + } + }); + }); + + $('#submitBtn').on('click', function() + { + $('#submitBtn').attr('disabled', true); + + var ldapData = $('#LDAPForm').serializeArray(); + $.post(createLink('system', 'installLDAP'), ldapData).done(function(response) + { + $('#submitBtn').attr('disabled', false); + + var res = JSON.parse(response); + if(res.result == 'success') + { + parent.window.location.href = res.locate; + } + else + { + $('#waiting').modal('hide'); + clearInterval(timerID); + + var errMessage = res.message; + if(res.message instanceof Array) errMessage = res.message.join('
'); + if(res.message instanceof Object) errMessage = Object.values(res.message).join('
'); + + bootbox.alert( + { + title: notices.fail, + message: errMessage, + }); + } + }); + }); +}); diff --git a/module/system/js/installsmtp.js b/module/system/js/installsmtp.js new file mode 100644 index 0000000000..a18e743352 --- /dev/null +++ b/module/system/js/installsmtp.js @@ -0,0 +1,91 @@ +$(function() +{ + /** + * Fresh submit btton by enable SMTP checkboc value and verified result of SMTP account. + * + * @access public + * @return void + */ + function freshSubmitBtn() + { + var enableSMTP = $('#smtpForm input[type=checkbox]:checked').length > 0; + var accountRight = $('#verifyAccountBtn').attr('pass') == 'true'; + + if(enableSMTP) + { + $('#smtpForm').find('table').show(); + $('#smtpForm').find('button[type=submit]').show(); + } + else + { + $('#smtpForm').find('table').hide(); + $('#smtpForm').find('button[type=submit]').hide(); + } + + if(enableSMTP && accountRight) + { + $('#smtpForm button[type=submit]').attr('disabled', false); + } + else + { + $('#smtpForm button[type=submit]').attr('disabled', true); + } + } + + $('#smtpForm input[type=checkbox]').on('change', function(event) + { + freshSubmitBtn(); + }); + + $('#smtpForm input[type=checkbox]').change(); + + $('#smtpForm input[type=text]').on('change', function(event) + { + $('#verifyAccountBtn').attr('pass', 'false'); + $('#verifyResult').text(''); + freshSubmitBtn(); + }); + + $('#verifyAccountBtn').on('click', function(event) + { + var settings = {}; + settings.host = $("input[name='host']").val(); + settings.port = $("input[name='port']").val(); + settings.user = $("input[name='user']").val(); + settings.pass = $("input[name='pass']").val(); + if(!settings.host || !settings.port || !settings.user || !settings.pass) + { + bootbox.alert( + { + title: notices.attention, + message: notices.fillAllRequiredFields, + }); + return; + } + + $.post(createLink('system', 'ajaxVerifySMTPAccount'), settings).done(function(response) + { + try + { + var res = JSON.parse(response); + } + catch(error) + { + var res = {result: 'fail', message: errors.verifySMTPFailed,}; + } + $('#verifyResult').html(res.message); + if(res.result == 'success') + { + $('#verifyAccountBtn').attr('pass', 'true'); + $('#verifyResult').removeClass('text-red').addClass('text-success'); + freshSubmitBtn(); + } + else + { + $('#verifyAccountBtn').attr('pass', 'false'); + $('#verifyResult').removeClass('text-success').addClass('text-red'); + freshSubmitBtn(); + } + }); + }); +}); diff --git a/module/system/js/ldapview.js b/module/system/js/ldapview.js new file mode 100644 index 0000000000..113ad5f7db --- /dev/null +++ b/module/system/js/ldapview.js @@ -0,0 +1,127 @@ +$(function() +{ + $('.btn-visit').on('click', function(event) + { + $.get(createLink('system', 'ajaxLdapInfo'), function(response) + { + let res = JSON.parse(response); + if(res.result == 'success') + { + $('#ldapAccount').text(res.data.account); + $('#ldapPassword').val(res.data.pass); + $('#ldapVisitUrl').attr('href', '//' + res.data.domain); + $('#ldapAccountModal').modal('show'); + } + }); + }); + + $('#ldapPassBtn').on('click', function(event){ + var inputTyep = $('#ldap_password').attr('type'); + if(inputTyep == 'text'){ + $('#ldap_password').attr('type', 'password'); + $('#ldapPassBtn').find('.icon').removeClass('icon-eye').addClass('icon-eye-off'); + } + else + { + $('#ldap_password').attr('type', 'text'); + $('#ldapPassBtn').find('.icon').addClass('icon-eye').removeClass('icon-eye-off'); + } + }); + + $('#copyPassBtn').on('click', function(event) + { + $('#ldapPassword').select(); + document.execCommand('copy'); + bootbox.alert(copySuccess); + }); + + $('.btn-start').on('click', function(event) + { + bootbox.confirm(instanceNotices.confirmStart, function(result) + { + if(!result) return; + + var loadingDialog = bootbox.dialog( + { + message: '
  ' + instanceNotices.starting + '
', + }); + + let id = $(event.target).closest('button').attr('instance-id'); + let url = createLink('instance', 'ajaxStart', 'id=' + id, 'json'); + $.post(url).done(function(response) + { + loadingDialog.modal('hide'); + + let res = JSON.parse(response); + if(res.result == 'success') + { + window.location.reload(); + } + else + { + bootbox.alert( + { + title: instanceNotices.fail, + message: res.message, + }); + } + }); + }); + }); + + $('.btn-stop').on('click', function(event) + { + bootbox.confirm(instanceNotices.confirmStop, function(result) + { + if(!result) return; + + var loadingDialog = bootbox.dialog( + { + message: '
  ' + instanceNotices.stopping + '
', + }); + + let id = $(event.target).closest('button').attr('instance-id'); + let url = createLink('instance', 'ajaxStop', 'id=' + id, 'json'); + $.post(url).done(function(response) + { + loadingDialog.modal('hide'); + + let res = JSON.parse(response); + if(res.result == 'success') + { + window.location.reload(); + } + else + { + bootbox.alert( + { + title: instanceNotices.fail, + message: res.message, + }); + } + }); + }); + }); + + setInterval(function() + { + var mainMenu = parent.window.$.apps.getLastApp(); + if(mainMenu.code != 'system') return; + + var statusURL = createLink('instance', 'ajaxStatus'); + $.post(statusURL, {idList: instanceIdList}).done(function(response) + { + let res = JSON.parse(response); + if(res.result == 'success' && res.data instanceof Array) + { + res.data.forEach(function(instance) + { + if($(".instance-status[instance-id=" + instance.id + "]").data('status') != instance.status) window.location.reload(); + }); + } + if(res.locate) window.parent.location.href = res.locate; + }); + }, 1000 * 5); + + $('[data-toggle="tooltip"]').tooltip(); +}); diff --git a/module/system/js/ossview.js b/module/system/js/ossview.js new file mode 100644 index 0000000000..66c388bc8c --- /dev/null +++ b/module/system/js/ossview.js @@ -0,0 +1,33 @@ +$(function() +{ + $('#ossManage').on('click', function(event) + { + $.get(createLink('system', 'ajaxOssInfo'), function(response) + { + let res = JSON.parse(response); + if(res.result == 'success') + { + $('#ossAdmin').text(res.data.account.username); + $('#ossPassword').val(res.data.account.password); + $('#ossVisitUrl').attr('href', res.data.url); + $('#ossAccountModal').modal('show'); + } + }); + }); + + $('#copySKBtn').on('click', function(event) + { + $('#ossSK').removeClass('hidden').select(); + document.execCommand('copy'); + $('#ossSK').addClass('hidden'); + bootbox.alert(copySuccess); + }); + + $('#copyPassBtn').on('click', function(event) + { + $('#ossPassword').removeClass('hidden').select(); + document.execCommand('copy'); + $('#ossPassword').addClass('hidden'); + bootbox.alert(copySuccess); + }); +}); diff --git a/module/system/js/smtpview.js b/module/system/js/smtpview.js new file mode 100644 index 0000000000..3b9eb96010 --- /dev/null +++ b/module/system/js/smtpview.js @@ -0,0 +1,110 @@ +$(function() +{ + $('#smtpPassBtn').on('click', function(event){ + var inputTyep = $('#smtp_password').attr('type'); + if(inputTyep == 'text'){ + $('#smtp_password').attr('type', 'password'); + $('#smtpPassBtn').find('.icon').removeClass('icon-eye').addClass('icon-eye-off'); + } + else + { + $('#smtp_password').attr('type', 'text'); + $('#smtpPassBtn').find('.icon').addClass('icon-eye').removeClass('icon-eye-off'); + } + }); + + $('.btn-start').on('click', function(event) + { + bootbox.confirm(instanceNotices.confirmStart, function(result) + { + if(!result) return; + + var loadingDialog = bootbox.dialog( + { + message: '
  ' + instanceNotices.starting + '
', + }); + + let id = $(event.target).closest('button').attr('instance-id'); + let url = createLink('instance', 'ajaxStart', 'id=' + id, 'json'); + $.post(url).done(function(response) + { + loadingDialog.modal('hide'); + + let res = JSON.parse(response); + if(res.result == 'success') + { + window.location.reload(); + } + else + { + bootbox.alert( + { + title: instanceNotices.fail, + message: res.message, + }); + } + }); + }); + }); + + $('.btn-stop').on('click', function(event) + { + bootbox.confirm(instanceNotices.confirmStop, function(result) + { + if(!result) return; + + var loadingDialog = bootbox.dialog( + { + message: '
  ' + instanceNotices.stopping + '
', + }); + + let id = $(event.target).closest('button').attr('instance-id'); + let url = createLink('instance', 'ajaxStop', 'id=' + id, 'json'); + $.post(url).done(function(response) + { + loadingDialog.modal('hide'); + + let res = JSON.parse(response); + if(res.result == 'success') + { + window.location.reload(); + } + else + { + bootbox.alert( + { + title: instanceNotices.fail, + message: res.message, + }); + } + }); + }); + }); + + var enableTimer = true; + window.parent.$(window.parent.document).on('showapp', function(event, app) + { + enableTimer = app.code == 'space'; + }); + + setInterval(function() + { + if(!enableTimer) return; + + var statusURL = createLink('instance', 'ajaxStatus'); + $.post(statusURL, {idList: instanceIdList}).done(function(response) + { + let res = JSON.parse(response); + if(res.result == 'success' && res.data instanceof Array) + { + res.data.forEach(function(instance) + { + if($(".instance-status[instance-id=" + instance.id + "]").data('status') != instance.status) window.location.reload(); + }); + } + if(res.locate) window.parent.location.href = res.locate; + }); + }, 1000 * 5); + + $('[data-toggle="tooltip"]').tooltip(); +}); diff --git a/module/system/lang/zh-cn.php b/module/system/lang/zh-cn.php new file mode 100644 index 0000000000..338c2ff95a --- /dev/null +++ b/module/system/lang/zh-cn.php @@ -0,0 +1,170 @@ +system->dashboard = '仪表盘'; +$lang->system->systemInfo = '系统信息'; +$lang->system->dbManagement = '数据库管理'; +$lang->system->ldapManagement = 'LDAP'; +$lang->system->dbList = '数据库列表'; +$lang->system->dbName = '名称'; +$lang->system->dbStatus = '状态'; +$lang->system->dbType = '类型'; +$lang->system->action = '操作'; +$lang->system->management = '管理'; +$lang->system->visit = '访问'; +$lang->system->close = '关闭'; +$lang->system->installLDAP = '安装LDAP'; +$lang->system->editLDAP = '编辑'; +$lang->system->LDAPInfo = 'LDAP信息'; +$lang->system->accountInfo = '账号信息'; +$lang->system->advance = '高级'; +$lang->system->verify = '校验'; +$lang->system->copy = '复制'; +$lang->system->copySuccess = '已复制到剪切板'; +$lang->system->cneStatus = '平台状态'; +$lang->system->cneStatistic = '资源统计'; +$lang->system->latestDynamic = '最新动态'; +$lang->system->nodeQuantity = '节点数'; +$lang->system->serviceQuantity = '服务数'; +$lang->system->cpuUsage = 'CPU(核)'; +$lang->system->memUsage = '内存(GB)'; + +/* LDAP */ +$lang->system->LDAP = new stdclass; +$lang->system->LDAP->info = 'LDAP信息'; +$lang->system->LDAP->ldapEnabled = '启用LDAP'; +$lang->system->LDAP->ldapQucheng = '渠成内置'; +$lang->system->LDAP->ldapSource = '来源'; +$lang->system->LDAP->ldapInstall = '安装并启用'; +$lang->system->LDAP->ldapUpdate = '更新'; +$lang->system->LDAP->accountInfo = '账号信息'; +$lang->system->LDAP->account = '账号'; +$lang->system->LDAP->password = '密码'; +$lang->system->LDAP->ldapUsername = '用户名'; +$lang->system->LDAP->ldapName = '名称'; +$lang->system->LDAP->host = '主机'; +$lang->system->LDAP->port = '端口'; +$lang->system->LDAP->account = '账号'; +$lang->system->LDAP->password = '密码'; +$lang->system->LDAP->ldapRoot = '根节点'; +$lang->system->LDAP->filterUser = '用户过滤'; +$lang->system->LDAP->email = '邮件字段'; +$lang->system->LDAP->extraAccount = '用户名字段'; +$lang->system->LDAP->ldapAdvance = '高级设置'; +$lang->system->LDAP->updateLDAP = '更新LDAP'; +$lang->system->LDAP->updateInstance = '更新已关联LDAP的服务'; +$lang->system->LDAP->updatingProgress = '更新中...剩余 %s 个服务。'; + +$lang->system->ldapTypeList = array(); +$lang->system->ldapTypeList['qucheng'] = '渠成内置'; +$lang->system->ldapTypeList['extra'] = '外部映射'; + +/* OSS */ +$lang->system->oss = new stdclass; +$lang->system->oss->common = '对象存储'; +$lang->system->oss->user = '用户名'; +$lang->system->oss->password = '密码'; +$lang->system->oss->manage = '管理'; +$lang->system->oss->apiURL = 'API地址'; +$lang->system->oss->accessKey = 'Access Key'; +$lang->system->oss->secretKey = 'Secret Key'; + +/* SMTP */ +$lang->system->SMTP = new stdclass; +$lang->system->SMTP->common = '邮箱配置'; +$lang->system->SMTP->enabled = '启用SMTP'; +$lang->system->SMTP->install = '安装'; +$lang->system->SMTP->update = '更新'; +$lang->system->SMTP->edit = '编辑'; +$lang->system->SMTP->editSMTP = '编辑SMTP'; +$lang->system->SMTP->account = '发信邮箱'; +$lang->system->SMTP->password = '密码'; +$lang->system->SMTP->host = 'SMTP服务器'; +$lang->system->SMTP->port = 'SMTP端口'; +$lang->system->SMTP->save = '保存'; + +/* Domain */ +$lang->system->customDomain = '新域名'; +$lang->system->certPem = '公钥证书'; +$lang->system->certKey = '私钥'; + +$lang->system->domain = new stdclass; +$lang->system->domain->common = '域名管理'; +$lang->system->domain->editDomain = '修改域名配置'; +$lang->system->domain->config = '配置域名和证书'; +$lang->system->domain->currentDomain = '当前域名'; +$lang->system->domain->oldDomain = '旧域名'; +$lang->system->domain->newDomain = '新域名'; +$lang->system->domain->expiredDate = '证书过期时间'; +$lang->system->domain->uploadCert = '上传证书(仅支持泛域名证书)'; + +$lang->system->domain->notReuseOldDomain = '使用自定义域名后无法改回默认域名'; +$lang->system->domain->setDNS = '建议修改域名前请先进行DNS解析,'; +$lang->system->domain->dnsHelperLink = '点击查看帮助文档'; +$lang->system->domain->updateInstancesDomain = '更新已安装服务的域名'; +$lang->system->domain->totalOldDomain = '共 %s 个。'; +$lang->system->domain->updatingProgress = '更新中...,剩余 %s 个,'; +$lang->system->domain->updating = '更新中...'; + +$lang->system->SLB = new stdclass; +$lang->system->SLB->common = '负载均衡'; +$lang->system->SLB->config = '配置负载均衡'; +$lang->system->SLB->edit = '修改负载均衡'; +$lang->system->SLB->ipPool = 'IP段'; +$lang->system->SLB->ipPoolExample = '示例:192.168.10.0/24或者192.168.10.0-192.168.10.100'; +$lang->system->SLB->installing = '正在配置负载均衡'; +$lang->system->SLB->leftSeconds = '预计剩余'; +$lang->system->SLB->second = '秒'; + +$lang->system->notices = new stdclass; +$lang->system->notices->success = '成功'; +$lang->system->notices->fail = '失败'; +$lang->system->notices->attention = '注意'; +$lang->system->notices->noLDAP = '找不到LDAP配置数据'; +$lang->system->notices->ldapUsed = '%s个服务已关联了LDAP'; +$lang->system->notices->ldapInstallSuccess = 'LDAP安装成功'; +$lang->system->notices->ldapUpdateSuccess = 'LDAP更新成功'; +$lang->system->notices->confirmUpdateLDAP = '修改LDAP后,会自动更新并重启已关联的服务,确定要修改吗?'; +$lang->system->notices->verifyLDAPSuccess = '校验LDAP成功!'; +$lang->system->notices->fillAllRequiredFields = '请填写全部必填项!'; +$lang->system->notices->smtpInstallSuccess = 'LDAP安装成功'; +$lang->system->notices->smtpUpdateSuccess = 'LDAP更新成功'; +$lang->system->notices->smtpWhiteList = '为防止邮件被屏蔽,请在邮件服务器里面将发信邮箱设为白名单'; +$lang->system->notices->smtpAuthCode = '有些邮箱要填写单独申请的授权码,具体请到邮箱相关设置查询'; +$lang->system->notices->smtpUsed = '%s 个服务关联了SMTP'; +$lang->system->notices->verifySMTPSuccess = '校验成功!'; +$lang->system->notices->pleaseCheckSMTPInfo = '校验失败!请检查用户名和密码是否正确'; +$lang->system->notices->confirmUpdateDomain = '修改域名后,会自动更新已安装服务的域名,确定要修改吗?'; +$lang->system->notices->updateDomainSuccess = '域名修改成功。'; +$lang->system->notices->configSLBSuccess = '配置负载均衡成功。'; +$lang->system->notices->validCert = '校验成功'; + +$lang->system->errors = new stdclass; +$lang->system->errors->notFoundDB = '找不到该数据库'; +$lang->system->errors->notFoundLDAP = '找不到LDAP数据'; +$lang->system->errors->dbNameIsEmpty = '数据库名为空'; +$lang->system->errors->notSupportedLDAP = '暂不支持该类型的LDAP'; +$lang->system->errors->failToInstallLDAP = '安装内置LDAP失败'; +$lang->system->errors->failToInstallExtraLDAP = '对接外部LDAP失败'; +$lang->system->errors->failToUpdateExtraLDAP = '更新外部LDAP失败'; +$lang->system->errors->failToUninstallQuChengLDAP = '卸载渠成内部LDAP失败'; +$lang->system->errors->failToUninstallExtraLDAP = '卸载外部LDAP失败'; +$lang->system->errors->failToDeleteLDAPSnippet = '删除LDAP片段失败'; +$lang->system->errors->verifyLDAPFailed = '校验LDAP失败'; +$lang->system->errors->LDAPLinked = '有服务已经关联了LDAP'; +$lang->system->errors->SMTPLinked = '有服务已经关联了SMTP服务'; +$lang->system->errors->failGetOssAccount = '获取对象存储账号失败'; +$lang->system->errors->failToInstallSMTP = '安装SMTP失败'; +$lang->system->errors->failToUninstallSMTP = '卸载SMTP失败'; +$lang->system->errors->failToUpdateSMTP = '更新SMTP失败'; +$lang->system->errors->verifySMTPFailed = '校验SMTP失败'; +$lang->system->errors->notFoundSMTPApp = '找不到SMTP代理应用'; +$lang->system->errors->notFoundSMTPService = '找不到SMTP代理服务'; +$lang->system->errors->domainIsRequired = '必须填写域名'; +$lang->system->errors->invalidDomain = '无效的域名或格式错误。域名只允许小写字母、数字、点(.)和中横线(-)'; +$lang->system->errors->failToUpdateDomain = '更新域名失败'; +$lang->system->errors->forbiddenOriginalDomain = '不能修改为平台默认域名'; +$lang->system->errors->newDomainIsSameWithOld = '新域名不能与原域名相同'; +$lang->system->errors->failedToConfigSLB = '配置负载均衡失败'; +$lang->system->errors->wrongIPRange = 'IP段格式错误,请参照示例格式,' . $lang->system->SLB->ipPoolExample; +$lang->system->errors->ippoolRequired = 'IP段不能为空'; +$lang->system->errors->failedToInstallSLBComponent = '安装负载均衡组件失败'; +$lang->system->errors->tryReinstallSLB = '安装负载均衡组件超时,请重试。'; diff --git a/module/system/model.php b/module/system/model.php new file mode 100644 index 0000000000..7b8056d5c8 --- /dev/null +++ b/module/system/model.php @@ -0,0 +1,943 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +class systemModel extends model +{ + /** + * Construct function: load setting model. + * + * @access public + * @return mixed + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('setting'); + } + + /** + * Get LDAP menu switcher. + * + * @access public + * @return string + */ + public function getLDAPSwitcher() + { + $output = "
"; + $output .= "{$this->lang->system->ldapManagement}"; + $output .= "
"; + + return $output; + } + + /** + * Get Oss menu switcher. + * + * @access public + * @return string + */ + public function getOssSwitcher() + { + $output = "
"; + $output .= "{$this->lang->system->oss->common}"; + $output .= "
"; + + return $output; + } + + /** + * Get SMTP menu switcher. + * + * @access public + * @return string + */ + public function getSMTPSwitcher() + { + $output = "
"; + $output .= "{$this->lang->system->SMTP->common}"; + $output .= "
"; + + return $output; + } + + /** + * Print action buttons. + * + * @param object $db + * @access public + * @return void + */ + public function printDBAction($db) + { + $disabled = strtolower($db->status) == 'running' ? '' : 'disabled'; + $btnHtml = html::commonButton($this->lang->system->management, "{$disabled} data-db-name='{$db->name}' data-db-type='{$db->db_type}' data-namespace='{$db->namespace}'", 'db-login btn btn-primary'); + + echo $btnHtml; + } + + /** + * Print edit LDAP button. + * + * @access public + * @return void + */ + public function printEditLDAPBtn() + { + $this->loadModel('instance'); + + $title = $this->lang->system->editLDAP; + $toolTips = ''; + $count = $this->instance->countLDAP(); + if($count) + { + $title = sprintf($this->lang->system->notices->ldapUsed, $count); + $toolTips = "data-toggle='tooltip' data-placement='bottom'"; + } + + $buttonHtml = ''; + $buttonHtml .= ""; + $buttonHtml .= html::a(inLink('editLDAP'), $this->lang->system->editLDAP, '', "title='{$title}' class='btn-edit btn label label-outline label-primary label-lg'"); + $buttonHtml .= ""; + + echo $buttonHtml; + } + + /** + * Print LDAP buttons. + * + * @param objevt $ldapInstance + * @access public + * @return mixed + */ + public function printLDAPButtons($ldapInstance) + { + $this->loadModel('instance'); + $this->app->loadLang('instance'); + + $buttonHtml = ''; + + if($ldapInstance->domain) + { + $disableVisit = !$this->instance->canDo('visit', $ldapInstance); + $buttonHtml .= html::commonButton($this->lang->instance->visit, "instance-id='{$ldapInstance->id}' title='{$this->lang->instance->visit}'" . ($disableVisit ? ' disabled ' : ''), 'btn-visit btn label label-outline label-primary label-lg'); + } + + $disableStart = !$this->instance->canDo('start', $ldapInstance); + $buttonHtml .= html::commonButton($this->lang->instance->start, "instance-id='{$ldapInstance->id}' title='{$this->lang->instance->start}'" . ($disableStart ? ' disabled ' : ''), "btn-start btn label label-outline label-primary label-lg"); + + $title = $this->lang->instance->stop; + $toolTips = ''; + $count = $this->instance->countLDAP(); + if($count) + { + $title = $this->lang->system->notices->ldapUsed; + $toolTips = "data-toggle='tooltip' data-placement='bottom' runat='server'"; + } + + $disableStop = $count > 0 || !$this->instance->canDo('stop', $ldapInstance); + $buttonHtml .= ""; + $buttonHtml .= html::commonButton($this->lang->instance->stop, "instance-id='{$ldapInstance->id}' title='{$title}'" . ($disableStop ? ' disabled ' : ''), 'btn-stop btn label label-outline label-danger label-lg'); + $buttonHtml .= ""; + + echo $buttonHtml; + } + + /** + * Install QuCheng LDAP. + * + * @param string $channel + * @access public + * @return bool|object + */ + public function installQuchengLDAP($ldapApp, $channel) + { + return $this->loadModel('instance')->installLDAP($ldapApp, '', 'OpenLDAP', $k8name = '', $channel); + } + + /** + * Update Qucheng LDAP. + * + * @param object $ldapApp + * @param string $channel + * @access public + * @return string + */ + public function updateQuchengLDAP($ldapApp, $channel) + { + $instanceID = $this->setting->getItem('owner=system&module=common§ion=ldap&key=instanceID'); + if($instanceID) + { + /* If QuCheng internal LDAP has been installed. Set QuCheng LDAP to be active. */ + return $this->setting->setItem('system.common.ldap.active', 'qucheng'); + } + else + { + /* If QuCheng internal LDAP has not been installed. */ + return $this->installQuchengLDAP($ldapApp, $channel); + } + } + + /** + * Install or update extra LDAP: it is creating a snippet in k8s system in fact. + * + * @param object $settings + * @access protected + * @return bool + */ + public function configExtraLDAP($settings) + { + if(!$this->testLDAPConnection($settings)) + { + dao::$errors[] = $this->lang->system->notSupportedLDAP; + return false; + } + + $space = $this->loadModel('space')->getSystemSpace($this->app->user->account); + + $snippetSettings = new stdclass; + $snippetSettings->name = 'snippet-extra-ldap'; + $snippetSettings->namespace = $space->k8space; + $snippetSettings->auto_import = false; + + $snippetSettings->values = new stdclass; + $snippetSettings->values->auth = new stdclass; + $snippetSettings->values->auth->ldap = new stdclass; + $snippetSettings->values->auth->ldap->enabled = true; + $snippetSettings->values->auth->ldap->type = 'ldap'; + $snippetSettings->values->auth->ldap->host = $settings->host; + $snippetSettings->values->auth->ldap->port = strval($settings->port); + $snippetSettings->values->auth->ldap->bindDN = "cn={$settings->bindDN},{$settings->baseDN}"; + $snippetSettings->values->auth->ldap->bindPass = $settings->bindPass; + $snippetSettings->values->auth->ldap->baseDN = $settings->baseDN; + $snippetSettings->values->auth->ldap->filter = html_entity_decode($settings->filter); + $snippetSettings->values->auth->ldap->attrUser = $settings->attrUser; + $snippetSettings->values->auth->ldap->attrEmail = $settings->attrEmail; + + $exists = $this->getExtraLDAPSettings(); + if(empty($exists)) + { + $snippetResult = $this->loadModel('cne')->addSnippet($snippetSettings); + if($snippetResult->code != 200) + { + dao::$errors[] = $this->lang->system->errors->failToInstallExtraLDAP; + return false; + } + } + else + { + $snippetResult = $this->loadModel('cne')->updateSnippet($snippetSettings); + if($snippetResult->code != 200) + { + dao::$errors[] = $this->lang->system->errors->failToUpdateExtraLDAP; + return false; + } + } + + /* Save extra LDAP setting to database. */ + $secretKey = helper::readKey(); + $encryptedPassword = openssl_encrypt($snippetSettings->values->auth->ldap->bindPass, 'DES-ECB', $secretKey); + $settings->bindPass = $encryptedPassword; + + $this->setting->setItem('system.common.ldap.active', 'extra'); + $this->setting->setItem('system.common.ldap.extraSnippetName', $snippetSettings->name); // Parameter for App installation API. + $this->setting->setItem('system.common.ldap.extraSettings', json_encode($settings)); + + return true; + } + + /** + * Update LDAP config and update instance. + * + * @param object $ldapApp + * @param string $channel + * @access public + * @return void + */ + public function updateLDAP($ldapApp, $channel) + { + $postData = fixer::input('post')->setDefault('source', 'qucheng')->get(); + if($postData->source == 'qucheng') + { + $success = $this->updateQuchengLDAP($ldapApp, $channel); + } + else if($postData->source == 'extra') + { + $success = $this->configExtraLDAP((object)$postData->extra); + if($success) $this->uninstallQuChengLDAP(true); + } + + if(!$success) return false; + + /* Update instances that has been enabled LDAP. */ + $instanceList = $this->loadModel('instance')->getListEnabledLDAP(); + $counter = count($instanceList); + foreach($instanceList as $instance) + { + $this->loadModel('setting')->setItem('system.common.ldap.updatingProgress', $counter); + $this->instance->switchLDAP($instance, true); + $counter-- ; + } + + $this->loadModel('setting')->deleteItems('owner=system&module=common§ion=ldap&key=updatingProgress'); + return true; + } + + /** + * Uninstall QuCheng LDAP. + * + * @param bool $force + * @access public + * @return bool + */ + public function uninstallQuChengLDAP($force = false) + { + if(!$force) + { + $ldapLinked = $this->loadModel('instance')->countLDAP(); + if($ldapLinked) + { + dao::$errors[] = $this->lang->system->errors->LDAPLinked; + return false; + } + } + + $instanceID = $this->setting->getItem('owner=system&module=common§ion=ldap&key=instanceID'); + $instance = $this->loadModel('instance')->getByID($instanceID); + if($instance) + { + /* 1. Uninstall QuCheng LDAP service. */ + if(!$this->loadModel('instance')->uninstall($instance)) + { + dao::$errors[] = $this->lang->system->errors->failToUninstallQuChengLDAP; + return false; + } + + /* 2. Remove snippet config map from CNE. */ + $space = $this->loadModel('space')->getSystemSpace($this->app->user->account); + + $apiParams = new stdclass; + $apiParams->name = 'snippet-qucheng-ldap'; + $apiParams->namespace = $space->k8space; + + $result = $this->loadModel('cne')->removeSnippet($apiParams); + if($result->code != 200) + { + dao::$errors[] = $this->lang->system->errors->failToUninstallQuChengLDAP; + return false; + } + } + + /* 3. Delete LDAP settings in database. */ + $this->setting->deleteItems('owner=system&module=common§ion=ldap&key=instanceID'); + $this->setting->deleteItems('owner=system&module=common§ion=ldap&key=snippetName'); + if($this->getActiveLDAP() == 'qucheng') $this->setting->deleteItems('owner=system&module=common§ion=ldap&key=active'); + + return true; + } + + /** + * Uninstall extra LDAP. + * + * @access public + * @return bool + */ + public function uninstallExtraLDAP() + { + $ldapLinked = $this->loadModel('instance')->countLDAP(); + if($ldapLinked) + { + dao::$errors[] = $this->lang->system->errors->LDAPLinked; + return false; + } + + /* 1. Remove snippet config map from CNE. */ + $space = $this->loadModel('space')->getSystemSpace($this->app->user->account); + + $apiParams = new stdclass; + $apiParams->name = 'snippet-extra-ldap'; + $apiParams->namespace = $space->k8space; + + $result = $this->loadModel('cne')->removeSnippet($apiParams); + if($result->code != 200) + { + dao::$errors[] = $this->lang->system->errors->failToDeleteLDAPSnippet; + return false; + } + + /* 2. Delete extra LDAP settings in database. */ + $this->setting->deleteItems('owner=system&module=common§ion=ldap&key=extraSettings'); + $this->setting->deleteItems('owner=system&module=common§ion=ldap&key=extraSnippetName'); + if($this->getActiveLDAP() == 'extra') $this->setting->deleteItems('owner=system&module=common§ion=ldap&key=active'); + + return true; + } + + /** + * Get extra LDAP settings. + * + * @access public + * @return object|array + */ + public function getExtraLDAPSettings() + { + $settings = $this->setting->getItem('owner=system&module=common§ion=ldap&key=extraSettings'); + $settings = @json_decode($settings); + if(empty($settings)) return array(); + + $secretKey = helper::readKey(); + $settings->bindPass = openssl_decrypt($settings->bindPass, 'DES-ECB', $secretKey); + return $settings; + } + + /** + * Test LDAP Connection by post settings. + * + * @param object $settings + * @access public + * @return bool + */ + public function testLDAPConnection($settings) + { + $connectID = ldap_connect("ldap://{$settings->host}:{$settings->port}"); + + if(!ldap_set_option($connectID, LDAP_OPT_PROTOCOL_VERSION, 3)) return false; + + return ldap_bind($connectID, "cn={$settings->bindDN},{$settings->baseDN}", $settings->bindPass); + } + + /** + * Has installed global LDAP or not. + * + * @access public + * @return bool + */ + public function hasSystemLDAP() + { + $activeLDAP = $this->setting->getItem('owner=system&module=common§ion=ldap&key=active'); + return $activeLDAP == 'extra' or $activeLDAP == 'qucheng'; // LDAP has been installed. + } + + /** + * Get global LDAP snippet name. + * + * @access public + * @return string + */ + public function ldapSnippetName() + { + $activeLDAP = $this->setting->getItem('owner=system&module=common§ion=ldap&key=active'); + + if($activeLDAP == 'extra') return $this->setting->getItem('owner=system&module=common§ion=ldap&key=extraSnippetName'); + + return $this->setting->getItem('owner=system&module=common§ion=ldap&key=snippetName'); + } + + /** + * Get active LDAP type. + * + * @access public + * @return string|null + */ + public function getActiveLDAP() + { + return $this->setting->getItem('owner=system&module=common§ion=ldap&key=active'); + } + + /** + * Check global SMTP is enabled or not. + * + * @access public + * @return bool + */ + public function isSMTPEnabled() + { + $smtpSnippetName = $this->smtpSnippetName(); + $enabled = $this->setting->getItem('owner=system&module=common§ion=smtp&key=enabled'); + + return $smtpSnippetName && $enabled; + } + + /** + * Get SMTP snippet name. + * + * @access public + * @return string + */ + public function smtpSnippetName() + { + return $this->setting->getItem('owner=system&module=common§ion=smtp&key=snippetName'); + } + + /** + * Get SMTP settings. + * + * @access public + * @return object + */ + public function getSMTPSettings() + { + $settingMap = json_decode($this->setting->getItem('owner=system&module=common§ion=smtp&key=settingsMap')); + if(empty($settingMap)) return new stdclass; + + $settings = $settingMap->env; + $settings->SMTP_PASS = openssl_decrypt($settings->SMTP_PASS, 'DES-ECB', helper::readKey()); + + //$snippetSettings = json_decode($this->setting->getItem('owner=system&module=common§ion=smtp&key=snippetSettings')); + + return $settings; + } + + /** + * Update SMTP settings. + * + * @access public + * @return void + */ + public function updateSMTPSettings() + { + $this->loadModel('cne'); + $this->loadModel('instance'); + + $channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel; + + $smtpSettings = fixer::input('post')->get(); + + $instanceID = $this->setting->getItem('owner=system&module=common§ion=smtp&key=instanceID'); + $instance = $this->instance->getByID($instanceID); + if(!$instance) + { + dao::$errors[] = $this->lang->system->errors->notFoundSMTPService; + return false; + } + + $instance->version = 'latest'; // Update and upgrade SMTP proxy instance. + + /* 1. Update SMTP service settings. */ + $settingsMap = new stdclass; + $settingsMap->env = new stdclass; + $settingsMap->env->SMTP_HOST = $smtpSettings->host; + $settingsMap->env->SMTP_PORT = strval($smtpSettings->port); + $settingsMap->env->SMTP_USER = $smtpSettings->user; + $settingsMap->env->SMTP_PASS = $smtpSettings->pass; + + $settings = new stdclass; + $settings->settings_map = $settingsMap; + + $success = $this->loadModel('cne')->updateConfig($instance, $settings); + if(!$success) + { + dao::$errors[] = $this->lang->system->errors->failToUpdateSMTP; + return false; + } + + /* 2. Save SMTP account. */ + $secretKey = helper::readKey(); + $settingsMap->env->SMTP_PASS = openssl_encrypt($settingsMap->env->SMTP_PASS, 'DES-ECB', $secretKey); + + $this->loadModel('setting'); + $this->setting->setItem('system.common.smtp.settingsMap', json_encode($settingsMap)); + + return true; + } + + /** + * Install global SMTP service. + * + * @param string $channel + * @access public + * @return bool + */ + public function installSysSMTP($channel = 'stable') + { + $settings = fixer::input('post')->get(); + + $smtpApp = $this->loadModel('store')->getAppInfoByChart('cne-courier', $channel, false); + if(empty($smtpApp)) + { + dao::$errors[] = $this->lang->system->notFoundSMTPApp; + return false; + } + + $result = $this->loadModel('instance')->installSysSMTP($smtpApp, $settings, 'cne-courier', '', $channel); + return $result; + } + + /** + * Uninstall system SMTP. + * + * @access public + * @return bool + */ + public function uninstallSysSMTP() + { + $smtpLinked = $this->loadModel('instance')->countSMTP(); + if($smtpLinked) + { + dao::$errors[] = $this->lang->system->errors->SMTPLinked; + return false; + } + + $instanceID = $this->setting->getItem('owner=system&module=common§ion=smtp&key=instanceID'); + $instance = $this->instance->getByID($instanceID); + if($instance) + { + /* 1. Uninstall QuCheng LDAP service. */ + if(!$this->loadModel('instance')->uninstall($instance)) + { + dao::$errors[] = $this->lang->system->errors->failToUninstallSMTP; + return false; + } + + /* 2. Remove snippet config map from CNE. */ + $space = $this->loadModel('space')->getSystemSpace($this->app->user->account); + + $apiParams = new stdclass; + $apiParams->name = 'snippet-smtp-proxy'; + $apiParams->namespace = $space->k8space; + + $result = $this->loadModel('cne')->removeSnippet($apiParams); + if($result->code != 200) + { + dao::$errors[] = $this->lang->system->errors->failToUninstallQuChengLDAP; + return false; + } + } + + /* 3. Delete SMTP settings in database. */ + $this->setting->deleteItems('owner=system&module=common§ion=smtp&key=enabled'); + $this->setting->deleteItems('owner=system&module=common§ion=smtp&key=instanceID'); + $this->setting->deleteItems('owner=system&module=common§ion=smtp&key=snippetName'); + $this->setting->deleteItems('owner=system&module=common§ion=smtp&key=settingsMap'); + $this->setting->deleteItems('owner=system&module=common§ion=smtp&key=snippetSettings'); + + return true; + } + + /** + * Get customized domain settings. * + * @access public + * @return object + */ + public function getDomainSettings() + { + $settings = new stdclass; + $settings->customDomain = $this->setting->getItem('owner=system&module=common§ion=domain&key=customDomain'); + $settings->https = $this->setting->getItem('owner=system&module=common§ion=domain&key=https'); + $settings->certPem = ''; // + $settings->certKey = ''; // + + return $settings; + } + + /** + * Save customized somain settings. + * + * @access public + * @return void + */ + public function saveDomainSettings() + { + $settings = fixer::input('post') + ->setDefault('customDomain', '') + ->setDefault('https', 'false') + ->setIf(is_array($this->post->https) && in_array('true', $this->post->https), 'https', 'true') + ->setDefault('certPem', '') + ->setDefault('certKey', '') + ->get(); + + $this->dao->from('system')->data($settings) + ->check('customDomain', 'notempty') + ->checkIf($settings->https == 'true', 'certPem', 'notempty') + ->checkIf($settings->https == 'true', 'certKey', 'notempty'); + if(dao::isError()) return; + + if(!validater::checkREG($settings->customDomain, '/^((?!-)[a-z0-9-]{1,63}(?lang->system->errors->invalidDomain; + return; + } + + /* Upload Certificate to CNE. */ + if($settings->https == 'true') + { + $cert = new stdclass; + $cert->name = 'tls-' . str_replace('.', '-', $settings->customDomain); + $cert->certificate_pem = $settings->certPem; + $cert->private_key_pem = $settings->certKey; + $certResult = $this->loadModel('cne')->uploadCert($cert); + if($certResult->code != 200) + { + dao::$errors[] = $certResult->message; + return; + } + } + + $oldSettings = $this->getDomainSettings(); + if($settings->customDomain == $oldSettings->customDomain) + { + dao::$errors[] = $this->lang->system->errors->newDomainIsSameWithOld; + return; + } + + if(stripos($settings->customDomain, 'haogs.cn') !== false) + { + dao::$errors[] = $this->lang->system->errors->forbiddenOriginalDomain; + return; + } + + $expiredDomain = $this->setting->getItem('owner=system&module=common§ion=domain&key=expiredDomain'); + $expiredDomain = empty($expiredDomain ) ? array(getenv('APP_DOMAIN')) : json_decode($expiredDomain, true); + $expiredDomain[] = zget($settings, 'customDomain', ''); + $this->setting->setItem('system.common.domain.expiredDomain', json_encode($expiredDomain)); + + $this->setting->setItem('system.common.domain.customDomain', zget($settings, 'customDomain', '')); + $this->setting->setItem('system.common.domain.https', zget($settings, 'https', 'false')); + + $this->loadModel('instance')->updateInstancesDomain(); + + $this->updateMinioDomain(); + } + + /** + * Update minio domain. + * + * @access public + * @return void + */ + public function updateMinioDomain() + { + $this->loadModel('cne'); + $sysDomain = $this->cne->sysDomain(); + + $minioInstance = new stdclass; + $minioInstance->k8name = 'cne-operator'; + $minioInstance->chart = 'cne-operator'; + $minioInstance->spaceData = new stdclass; + $minioInstance->spaceData->k8space = $this->config->k8space; + + $settings = new stdclass; + $settings->settings_map = new stdclass; + $settings->settings_map->minio = new stdclass; + $settings->settings_map->minio->ingress = new stdclass; + $settings->settings_map->minio->ingress->enabled = true; + $settings->settings_map->minio->ingress->host = 's3.' . $sysDomain; + + $this->cne->updateConfig($minioInstance, $settings); + } + + /** + * Get SLB settings. + * + * @access public + * @return object + */ + public function getSLBSettings() + { + $settings = new stdclass; + $settings->instanceID = $this->setting->getItem('owner=system&module=common§ion=slb&key=instanceID'); + $settings->name = $this->setting->getItem('owner=system&module=common§ion=slb&key=name'); + $settings->ippool = ''; + + if($settings->instanceID) + { + $slbInstance = $this->loadModel('instance')->getByID($settings->instanceID); + + $qlbInfo = $this->loadmodel('cne')->getQLBinfo($settings->name, $slbInstance->spaceData->k8space); // QLB: Qucheng load balancer. + if($qlbInfo) $settings->ippool = $qlbInfo->ippool; + } + + return $settings; + } + + /** + * Save SLB settings. + * + * @access public + * @return void + */ + public function saveSLBSettings() + { + $settings = fixer::input('post') + ->setDefault('ippool', '') + ->get(); + if(empty($settings->ippool)) + { + dao::$errors[] = $this->lang->system->errors->ippoolRequired; + return; + } + + $reg1Result = validater::checkREG($settings->ippool, '/^((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}\/\d{1,2}$/'); + $reg2Result = validater::checkREG($settings->ippool, '/^(((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3})-(((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3})$/'); + if($reg1Result === false && $reg2Result === false) + { + dao::$errors[] = $this->lang->system->errors->wrongIPRange; + return; + } + + $instanceID = $this->setting->getItem('owner=system&module=common§ion=slb&key=instanceID'); + if(!$instanceID) + { + /* 1. Install SLB component metallb at first time. */ + $slbInstance = $this->installSLBInstance(); + if(!$slbInstance) return; + + $instanceID = $slbInstance->id; + $this->setting->setItem('system.common.slb.instanceID', $slbInstance->id); + } + + $instance = $this->loadModel('instance')->getByID($instanceID); + $status = ''; + /* Wait 30 seconds at most for SLB instance ready. */ + for($times = 0; $times < 10; $times++) + { + sleep(3); + $statusResponse = $this->loadModel('cne')->queryStatus($instance); + if($statusResponse->code != 200) continue; + + $status = $statusResponse->data->status; + if($status == 'running') break; + } + + if($status != 'running') + { + dao::$errors[] = $this->lang->system->errors->tryReinstallSLB; + return; + } + + /* 2. Config SLB. */ + $settings->name = 'qlb-quickon'; + $settings->namespace = $this->config->k8space; + $success = $this->loadModel('cne')->configQLB($settings); + if(!$success) + { + dao::$errors[] = $this->lang->system->errors->failedToConfigSLB; + return; + } + + $this->setting->setItem('system.common.slb.name', zget($settings, 'name', '')); + } + + /** + * Install SLB instance. + * + * @access private + * @return object|null + */ + private function installSLBInstance() + { + $channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel; + + $slbApp = new stdclass; + $slbApp->name = 'metallb'; + $slbApp->alias = 'metallb'; + $slbApp->desc = 'metallb'; + $slbApp->chart = 'metallb'; + $slbApp->app_version = ''; + $slbApp->version = ''; + $slbApp->id = ''; + $slbApp->logo = ''; + + $slbInstance = $this->loadModel('instance')->installSysSLB($slbApp, 'cne-lb', $channel); + if(!$slbInstance) + { + dao::$errors[] = $this->lang->system->errors->failedToInstallSLBComponent; + return; + } + + return $slbInstance; + } + + /** + * Print SMTP buttons. + * + * @param objevt $smtpInstance + * @access public + * @return string + */ + public function printSMTPButtons($smtpInstance) + { + $this->loadModel('instance'); + $this->app->loadLang('instance'); + + $buttonHtml = ''; + + $disableStart = !$this->instance->canDo('start', $smtpInstance); + $buttonHtml .= html::commonButton($this->lang->instance->start, "instance-id='{$smtpInstance->id}' title='{$this->lang->instance->start}'" . ($disableStart ? ' disabled ' : ''), "btn-start btn label label-outline label-primary label-lg"); + + $title = $this->lang->instance->stop; + $toolTips = ''; + $count = $this->instance->countSMTP(); + if($count) + { + $title = sprintf($this->lang->system->notices->smtpUsed, $count); + $toolTips = "data-toggle='tooltip' data-placement='bottom' runat='server'"; + } + + $buttonHtml .= ""; + $buttonHtml .= html::a(inLink('editSMTP'), $this->lang->system->SMTP->edit, '', "title='{$title}' class='btn-edit btn label label-outline label-primary label-lg'"); + $buttonHtml .= ""; + + $disableStop = $count > 0 || !$this->instance->canDo('stop', $smtpInstance); + $buttonHtml .= ""; + $buttonHtml .= html::commonButton($this->lang->instance->stop, "instance-id='{$smtpInstance->id}' title='{$title}'" . ($disableStop ? ' disabled ' : ''), 'btn-stop btn label label-outline label-danger label-lg'); + $buttonHtml .= ""; + + echo $buttonHtml; + } + + public function getK8sTag() + { + $serviceAccount = '/var/run/secrets/kubernetes.io/serviceaccount'; + if(!is_dir($serviceAccount)) return "Fail: Please run script in k8s."; + + $nameSpace = file_get_contents($serviceAccount . '/namespace'); + + $apiServer = empty($_POST['apiServer']) ? 'https://kubernetes.default.svc' : $_POST['apiServer']; + $token = file_get_contents($serviceAccount . '/token'); + $cacert = $serviceAccount . '/ca.crt'; + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, "$apiServer/api/v1/namespaces/{$nameSpace}/serviceaccounts/default"); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_CAINFO, $cacert); + curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: Bearer $token")); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET'); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLINFO_HEADER_OUT, true); + $response = curl_exec($curl); + $errors = curl_error($curl); + curl_close($curl); + + if($errors) return "Fail: " . $errors; + + $serviceAccounts = json_decode($response); + if(empty($serviceAccounts->metadata->uid)) + { + if($serviceAccounts->code == '403') return $this->lang->misc->k8s->repairNotice; + return "Fail: " . $response; + } + + $infos = array(); + $infos['apiServer'] = $apiServer; + $infos['nameSpace'] = $nameSpace; + $infos['uid'] = ''; + if(isset($serviceAccounts->metadata->uid)) $infos['uid'] = $serviceAccounts->metadata->uid; + + if(empty($infos['uid'])) return "Fail: Can not find k8s uid information"; + + $md5 = md5($this->config->global->sn); + $systemDebug = $this->config->debug; + $this->config->debug = false; + $encrypted = @openssl_encrypt(json_encode($infos), 'DES-CBC', substr($md5, 0, 8)); + $this->config->debug = $systemDebug; + return $encrypted; + } +} diff --git a/module/system/view/dashboard.html.php b/module/system/view/dashboard.html.php new file mode 100644 index 0000000000..0db1a8d76e --- /dev/null +++ b/module/system/view/dashboard.html.php @@ -0,0 +1,20 @@ + + * @package my + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +
+
+
+
+
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> diff --git a/module/system/view/dblist.html.php b/module/system/view/dblist.html.php new file mode 100644 index 0000000000..f5697c2293 --- /dev/null +++ b/module/system/view/dblist.html.php @@ -0,0 +1,43 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> + +
+
+
+

system->dbList;?>

+
+ + + + + + + + + + + + + + + +
system->dbName;?>system->dbType;?>system->dbStatus;?>system->action?>
name;?>db_type?>instance->statusList, $db->status);?>system->printDBAction($db);?>
+
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> + diff --git a/module/system/view/domainview.html.php b/module/system/view/domainview.html.php new file mode 100644 index 0000000000..dbf06aa211 --- /dev/null +++ b/module/system/view/domainview.html.php @@ -0,0 +1,43 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> + +
+
+
+

system->domain->common;?>

+
+ inLink('editDomain'), $lang->system->domain->editDomain, '', "class='btn btn-primary'");?> +
+
+ + + + + + + + + + + + + +
system->domain->currentDomain;?>
system->domain->expiredDate;?>
+
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> diff --git a/module/system/view/editdomain.html.php b/module/system/view/editdomain.html.php new file mode 100644 index 0000000000..03ad29d67c --- /dev/null +++ b/module/system/view/editdomain.html.php @@ -0,0 +1,97 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> + +system->errors);?> +system->notices);?> + +
+
+
+

system->domain->config;?>

+
+
+ + + + + + + + + + + + + + + + + + +
system->domain->oldDomain;?>loadModel('cne')->sysDomain();?> system->domain->notReuseOldDomain;?>
system->domain->newDomain;?> + +
+ system->domain->setDNS;?> + system->domain->dnsHelperLink, '_blank', "class='text-primary'");?> +
+
+

+ + $lang->system->domain->uploadCert), $domainSettings->https, ($domainUsed ? "onclick='return false;'" : ''));?> +

+
+ + + + + + + + + + + + + + + + + + +
system->certPem;?>
system->certKey;?>
+ system->verify, "id='validateCertBtn'");?> + +
+
save, "id='submitBtn'", "btn btn-primary");?>
+
+
+
+ +app->getModuleRoot() . '/common/view/footer.html.php';?> + diff --git a/module/system/view/editldap.html.php b/module/system/view/editldap.html.php new file mode 100644 index 0000000000..c3c0b16bcd --- /dev/null +++ b/module/system/view/editldap.html.php @@ -0,0 +1,32 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +loadModel('instance')->countLDAP();?> +system->errors);?> +system->notices);?> + + +
+
+
+

system->ldapManagement;?>

+
+ +
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> + diff --git a/module/system/view/editslb.html.php b/module/system/view/editslb.html.php new file mode 100644 index 0000000000..b31992d53d --- /dev/null +++ b/module/system/view/editslb.html.php @@ -0,0 +1,58 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> + +system->errors);?> +system->notices);?> + +
+
+
+

system->SLB->config;?>

+
+
+ + + + + + + + +
system->SLB->ipPool;?> + system->SLB->ipPoolExample}'");?> +
+
save, "id='submitBtn'", 'btn btn-wide btn-primary');?>
+
+
+
+ +app->getModuleRoot() . '/common/view/footer.html.php';?> + diff --git a/module/system/view/editsmtp.html.php b/module/system/view/editsmtp.html.php new file mode 100644 index 0000000000..edd8c1be2e --- /dev/null +++ b/module/system/view/editsmtp.html.php @@ -0,0 +1,32 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +loadModel('instance')->countSMTP();?> +system->errors);?> +system->notices);?> + + +
+
+
+

system->SMTP->editSMTP;?>

+
+ +
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> + diff --git a/module/system/view/index.html.php b/module/system/view/index.html.php new file mode 100644 index 0000000000..a76bff722e --- /dev/null +++ b/module/system/view/index.html.php @@ -0,0 +1,76 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> + +app->getModuleRoot() . '/common/view/footer.html.php';?> diff --git a/module/system/view/installldap.html.php b/module/system/view/installldap.html.php new file mode 100644 index 0000000000..33272e3546 --- /dev/null +++ b/module/system/view/installldap.html.php @@ -0,0 +1,31 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +loadModel('instance')->countLDAP();?> +system->errors);?> +system->notices);?> + +
+
+
+

system->installLDAP;?>

+
+ +
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> + diff --git a/module/system/view/installsmtp.html.php b/module/system/view/installsmtp.html.php new file mode 100644 index 0000000000..3fc433875f --- /dev/null +++ b/module/system/view/installsmtp.html.php @@ -0,0 +1,31 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +loadModel('instance')->countSMTP();?> +system->errors);?> +system->notices);?> + +
+
+
+

system->SMTP->install;?>

+
+ +
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> + diff --git a/module/system/view/instancesblock.html.php b/module/system/view/instancesblock.html.php new file mode 100644 index 0000000000..eb6703a917 --- /dev/null +++ b/module/system/view/instancesblock.html.php @@ -0,0 +1,43 @@ +app->loadLang('instance');?> + +
+

instance->runningService;?>

+ +
+

instance->empty;?>

+
+ + + + + + + + + + + + + + + + + + id);?> + + + + + +
instance->name;?>instance->version;?>instance->status?>instance->cpu;?>instance->mem;?>
createLink('instance', 'view', "id=$instance->id"), $instance->name);?>appVersion;?> + instance->printStatus($instance, false);?> + + + instance->leftTime;?> + 00:00 + + + instance->printCpuUsage($instance, $metrics->cpu);?>instance->printMemUsage($instance, $metrics->memory);?>
+ + +
diff --git a/module/system/view/ldapform.html.php b/module/system/view/ldapform.html.php new file mode 100644 index 0000000000..9738a56434 --- /dev/null +++ b/module/system/view/ldapform.html.php @@ -0,0 +1,98 @@ +
+

+ system->hasSystemLDAP();?> + $lang->system->LDAP->ldapEnabled), $enableLDAP ? 'true' : '', (($ldapLinked or $activeLDAP) ? "onclick='return false;'" : '')); ?> +

+ + + + + + + + +
system->LDAP->ldapSource;?>system->ldapTypeList, $activeLDAP,"class='form-control'");?>
+ + + + + + + + + + + +
system->LDAP->ldapUsername?>account->username;?>
system->LDAP->ldapRoot;?>
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
system->LDAP->host;?>
system->LDAP->port;?>
system->LDAP->ldapUsername;?>
system->LDAP->password;?>
system->LDAP->ldapRoot;?>
+
system->LDAP->ldapAdvance . "", '', "data-toggle='collapse'");?>
+ + + + + + + + + + + + + + + + + + +
system->LDAP->filterUser;?>
system->LDAP->email;?>
system->LDAP->extraAccount;?>
+ + + + + + + + +
system->verify, "id='testConnectBtn'");?>
+
+
system->LDAP->ldapUpdate : $lang->system->LDAP->ldapInstall, "id='submitBtn'", "btn btn-primary btn-wide");?>
+
+ diff --git a/module/system/view/ldapview.html.php b/module/system/view/ldapview.html.php new file mode 100644 index 0000000000..048c902100 --- /dev/null +++ b/module/system/view/ldapview.html.php @@ -0,0 +1,132 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +instance->notices);?> + +system->copySuccess);?> + +
+
+
+

system->LDAP->info;?>

+
+ system->printEditLDAPBtn();?> + + system->printLDAPButtons($ldapInstance);?> + + system->visit, '', "disabled class='btn label label-outline label-primary label-lg'");?> + system->close, '', "disabled class='btn label label-outline label-primary label-lg'");?> + +
+
+ + + + + + + + + + + + + + + + + + + + + +
system->LDAP->ldapSource;?>system->ldapTypeList, $activeLDAP, '');?>
system->LDAP->ldapUsername;?>auth, 'username', '');?>
system->LDAP->ldapRoot;?>auth, 'root', '');?>
instance->status;?>instance->statusList, $ldapInstance->status, '');?>
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
system->LDAP->ldapSource;?>system->ldapTypeList, $activeLDAP, '');?>
system->LDAP->host;?>
system->LDAP->port;?>
system->LDAP->ldapUsername;?>
system->LDAP->password;?> +
+ + +
+
system->LDAP->ldapRoot;?>
system->LDAP->ldapAdvance;?>
system->LDAP->filterUser;?>
system->LDAP->email;?>
system->LDAP->extraAccount;?>
+ +
+
+ +app->getModuleRoot() . '/common/view/footer.html.php';?> diff --git a/module/system/view/ossview.html.php b/module/system/view/ossview.html.php new file mode 100644 index 0000000000..f0a2822c97 --- /dev/null +++ b/module/system/view/ossview.html.php @@ -0,0 +1,69 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +system->copySuccess);?> + +
+
+
+

system->oss->common;?>

+
+ system->oss->manage, "id='ossManage'", "btn label label-outline label-primary label-lg");?> +
+
+ + + + + + + + + + + + + + + + +
system->oss->apiURL;?>extra_hosts, 'api', '');?>
system->oss->accessKey;?>username;?>
system->oss->secretKey;?> + + system->copy, "id='copySKBtn'");?> +
+
+
+ +app->getModuleRoot() . '/common/view/footer.html.php';?> diff --git a/module/system/view/overviewblock.html.php b/module/system/view/overviewblock.html.php new file mode 100644 index 0000000000..5b868bb7b6 --- /dev/null +++ b/module/system/view/overviewblock.html.php @@ -0,0 +1,32 @@ +app->loadLang('cne');?> +
+
+
+

system->cneStatus;?>

+
lang->CNE->statusIcons, $cneMetrics->status, $this->lang->CNE->statusIcons['unknown']);?>
+
CNE->statusList, $cneMetrics->status, $lang->CNE->statusList['unknown']);?>
+
+
+

system->cneStatistic;?>

+
+
+
system->nodeQuantity;?>
+
node_count;?>
+
+
+
system->serviceQuantity;?>
+
instance->totalServices();?>
+
+
+
system->cpuUsage;?>
+ cne->printCpuUsage($cneMetrics->metrics->cpu);?> +
+
+
system->memUsage;?>
+ cne->printMemUsage($cneMetrics->metrics->memory);?> +
+
+
+
+
+ diff --git a/module/system/view/slbview.html.php b/module/system/view/slbview.html.php new file mode 100644 index 0000000000..28da2501da --- /dev/null +++ b/module/system/view/slbview.html.php @@ -0,0 +1,38 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> + +
+
+
+

system->SLB->common;?>

+
+ inLink('editSLB'), $lang->system->SLB->edit, '', "class='btn btn-primary'");?> +
+
+ + + + + + + + +
system->SLB->ipPool;?>
+
+
+app->getModuleRoot() . '/common/view/footer.html.php';?> diff --git a/module/system/view/smtpform.html.php b/module/system/view/smtpform.html.php new file mode 100644 index 0000000000..a95ed09ae0 --- /dev/null +++ b/module/system/view/smtpform.html.php @@ -0,0 +1,36 @@ +
+

+ system->smtpSnippetName();?> + $lang->system->SMTP->enabled), $enableSMTP ? 'true' : '', (($smtpLinked or $activeSMTP) ? "onclick='return false;'" : ''));?> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
system->SMTP->account;?>
system->SMTP->password;?>
system->SMTP->host;?>
system->SMTP->port;?>
system->verify, "id='verifyAccountBtn'");?>
+
system->SMTP->update : $lang->system->SMTP->install);?>
+
diff --git a/module/system/view/smtpview.html.php b/module/system/view/smtpview.html.php new file mode 100644 index 0000000000..1efc99e40e --- /dev/null +++ b/module/system/view/smtpview.html.php @@ -0,0 +1,60 @@ + + * @package system + * @version $Id$ + * @link https://www.qucheng.com + */ +?> +app->getModuleRoot() . '/common/view/header.html.php';?> +instance->notices);?> +id));?> + +
+
+
+

system->SMTP->common;?>

+
+ system->printSMTPButtons($smtpInstance);?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
system->SMTP->account;?>
system->SMTP->password;?> +
+ + +
+
system->SMTP->host;?>
system->SMTP->port;?>
instance->status;?>instance->statusList, $smtpInstance->status, '');?>
+
+
+app->getModuleRoot() . '/common/view/footer.html.php';?>