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 <<
+
+
+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 = "";
+
+ return $output;
+ }
+
+ /**
+ * Get Oss menu switcher.
+ *
+ * @access public
+ * @return string
+ */
+ public function getOssSwitcher()
+ {
+ $output = "";
+
+ return $output;
+ }
+
+ /**
+ * Get SMTP menu switcher.
+ *
+ * @access public
+ * @return string
+ */
+ public function getSMTPSwitcher()
+ {
+ $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';?>
+
+
+ createLink('system', 'index'), " " . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
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';?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
system->domain->common;?>
+
+ inLink('editDomain'), $lang->system->domain->editDomain, '', "class='btn btn-primary'");?>
+
+
+
+
+
+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);?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
system->domain->config;?>
+
+
+
+
+
+
+
+
+
system->domain->updateInstancesDomain;?>
+
+ system->domain->updating;?>
+
+
+
+
+
+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);?>
+
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
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);?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
system->SLB->config;?>
+
+
+
+
+
+
+
+
+
system->SLB->installing;?>
+
+ system->SLB->leftSeconds;?>
+
+ system->SLB->second;?>
+
+
+
+
+
+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);?>
+
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
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';?>
+
+
+
+
+
+
+
+
+
+
+
+ edition == 'biz'):?>
+
+
+
+
+
+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);?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
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);?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
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->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
+
+
+ |
+ id);?>
+ 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->LDAP->updateLDAP;?>
+
+
+
+
+
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);?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
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->accountInfo;?>
+
system->LDAP->account;?>:
+
+ system->LDAP->password;?>:
+ system->copy, "id='copyPassBtn'", "btn bnt-link");?>
+
+
+
+ cancel, "data-dismiss='modal'", 'btn btn-wide');?>
+ system->visit, '_blank', "id='ldapVisitUrl' class='btn btn-primary btn-wide'");?>
+
+
+
+
+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);?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
system->oss->common;?>
+
+ system->oss->manage, "id='ossManage'", "btn label label-outline label-primary label-lg");?>
+
+
+
+
+
+
+
+
+
+
+
system->accountInfo;?>
+
system->oss->user;?>:
+
+ system->oss->password;?>:
+ system->copy, "id='copyPassBtn'", 'btn btn-link');?>
+
+
+ cancel, "data-dismiss='modal'", 'btn btn-wide');?>
+ system->visit, '_blank', "id='ossVisitUrl' class='btn btn-primary btn-wide'");?>
+
+
+
+
+
+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';?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
system->SLB->common;?>
+
+ inLink('editSLB'), $lang->system->SLB->edit, '', "class='btn btn-primary'");?>
+
+
+
+
+
+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 @@
+
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));?>
+
+
+ createLink('system', 'index'), "" . $lang->goback, '', "class='btn btn-secondary'");?>
+
+
+
+
+
+
system->SMTP->common;?>
+
+ system->printSMTPButtons($smtpInstance);?>
+
+
+
+
+
+app->getModuleRoot() . '/common/view/footer.html.php';?>