diff --git a/config/config.php b/config/config.php index 083f134ff5..61f40b515f 100644 --- a/config/config.php +++ b/config/config.php @@ -165,8 +165,10 @@ $config->maxCount = 500; $config->moreLinks = array(); /* 渠成平台设置。CNE Api settings. */ -$config->demoAccounts = ''; // 用于演示的账号列表,该账号安装的应用30钟后会自动删除。 In account list for demo, app instance of demo will be removed in 30 minutes. -$config->demoAppLife = 30; // Demo安装的应用实例存续时长(分钟)。The minutes life of instance which demo account installed. +$config->inQuickon = false; +$config->inContainer = false; +$config->demoAccounts = ''; // 用于演示的账号列表,该账号安装的应用30钟后会自动删除。 In account list for demo, app instance of demo will be removed in 30 minutes. +$config->demoAppLife = 30; // Demo安装的应用实例存续时长(分钟)。The minutes life of instance which demo account installed. $config->CNE = new stdclass(); $config->CNE->api = new stdclass(); $config->CNE->api->host = ''; diff --git a/db/update20.0.sql b/db/update20.0.sql index 1e6f28e432..29ac6a8874 100644 --- a/db/update20.0.sql +++ b/db/update20.0.sql @@ -117,8 +117,6 @@ CREATE TABLE IF NOT EXISTS `zt_solution` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -REPLACE INTO `zt_space` (`id`, `name`,`k8space`,`owner`,`default`,`createdAt`) VALUES (1, 'default space', 'quickon-app', 'qadmin', 1, current_date()); - CREATE TABLE IF NOT EXISTS `zt_session` ( `id` varchar(32) NOT NULL, `data` mediumtext, diff --git a/db/zentao.sql b/db/zentao.sql index 7e8b32f101..24c200763b 100755 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -14407,8 +14407,6 @@ CREATE TABLE IF NOT EXISTS `zt_solution` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -REPLACE INTO `zt_space` (`id`, `name`,`k8space`,`owner`,`default`,`createdAt`) VALUES (1, 'default space', 'quickon-app', 'qadmin', 1, current_date()); - DROP FUNCTION IF EXISTS `get_monday`; CREATE FUNCTION `get_monday`(day date) RETURNS date begin if date_format(day, '%w') = 0 then return subdate(day, date_format(day, '%w') - 6)__DELIMITER__ diff --git a/module/admin/config.php b/module/admin/config.php index 55803bd76c..9cd0560666 100755 --- a/module/admin/config.php +++ b/module/admin/config.php @@ -7,7 +7,7 @@ $config->admin->log->saveDays = 30; if(!isset($config->safe)) $config->safe = new stdclass(); if(!isset($config->safe->weak)) $config->safe->weak = '123456,password,12345,12345678,qwerty,123456789,1234,1234567,abc123,111111,123123'; -$config->admin->menuGroup['system'] = array('custom|mode', 'backup', 'cron', 'action|trash', 'admin|xuanxuan', 'setting|xuanxuan', 'admin|license', 'admin|checkweak', 'admin|resetpwdsetting', 'admin|safe', 'custom|timezone', 'search|buildindex', 'admin|tableengine', 'ldap', 'custom|libreoffice', 'conference', 'client'); +$config->admin->menuGroup['system'] = array('custom|mode', 'backup', 'cron', 'action|trash', 'admin|xuanxuan', 'setting|xuanxuan', 'admin|license', 'admin|checkweak', 'admin|resetpwdsetting', 'admin|safe', 'custom|timezone', 'search|buildindex', 'admin|tableengine', 'ldap', 'custom|libreoffice', 'conference', 'client', 'system|browsebackup', 'system|restorebackup'); $config->admin->menuGroup['company'] = array('dept', 'company', 'user', 'group', 'tutorial'); $config->admin->menuGroup['switch'] = array('admin|setmodule'); $config->admin->menuGroup['model'] = array('auditcl', 'stage', 'design', 'cmcl', 'reviewcl', 'custom|required', 'custom|set', 'custom|flow', 'custom|code', 'custom|percent','custom|estimate', 'custom|hours', 'subject', 'process', 'activity', 'zoutput', 'classify', 'holiday', 'reviewsetting'); diff --git a/module/admin/lang/menu.php b/module/admin/lang/menu.php index d1071d3df1..466ee9b000 100644 --- a/module/admin/lang/menu.php +++ b/module/admin/lang/menu.php @@ -46,7 +46,6 @@ $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|browsebackup'; $lang->admin->menuList->platform['order'] = 55; $lang->admin->menuList->system['subMenu']['mode'] = array('link' => "{$lang->custom->mode}|custom|mode|"); @@ -183,17 +182,17 @@ $lang->admin->menuList->dev['menuOrder']['20'] = 'editor'; $lang->admin->menuList->dev['menuOrder']['25'] = 'entry'; //$lang->admin->menuList->platform['subMenu']['dashboard'] = array('link' => "{$lang->dashboard}|system|dashboard|"); -$lang->admin->menuList->platform['subMenu']['plat'] = array('link' => "{$lang->devops->platform}|system|browsebackup|", 'subModule' => 'system'); +$lang->admin->menuList->platform['subMenu']['plat'] = array('link' => "{$lang->devops->platform}|system|dblist|", 'subModule' => 'system'); //$lang->admin->menuList->platform['subMenu']['environment'] = array('link' => "{$lang->devops->environment}|gitlab|browse|", 'subModule' => 'gitlab,jenkins,sonarqube,gitea,gogs', 'alias' => 'create,edit,import'); $lang->admin->menuList->platform['subMenu']['resource'] = array('link' => "{$lang->devops->resource}|host|browse|", 'subModule' => 'host,account,serverroom,ops,tree'); $lang->admin->menuList->platform['subMenu']['setrules'] = array('link' => "{$lang->devops->rules}|repo|setrules|"); -$lang->admin->menuList->platform['tabMenu']['plat']['backup'] = array('link' => "{$lang->backup->common}|system|browsebackup|"); +//$lang->admin->menuList->platform['tabMenu']['plat']['backup'] = array('link' => "{$lang->backup->common}|system|browsebackup|"); $lang->admin->menuList->platform['tabMenu']['plat']['dblist'] = array('link' => "{$lang->devops->dblist}|system|dblist|"); $lang->admin->menuList->platform['tabMenu']['plat']['domain'] = array('link' => "{$lang->devops->domain}|system|configdomain|", 'alias' => 'editdomain,domainview'); $lang->admin->menuList->platform['tabMenu']['plat']['oss'] = array('link' => "{$lang->devops->oss}|system|ossview|"); -$lang->admin->menuList->platform['tabMenu']['menuOrder']['plat']['5'] = 'backup'; +//$lang->admin->menuList->platform['tabMenu']['menuOrder']['plat']['5'] = 'backup'; $lang->admin->menuList->platform['tabMenu']['menuOrder']['plat']['10'] = 'dblist'; $lang->admin->menuList->platform['tabMenu']['menuOrder']['plat']['15'] = 'domain'; $lang->admin->menuList->platform['tabMenu']['menuOrder']['plat']['20'] = 'oss'; @@ -285,3 +284,8 @@ if($config->vision == 'lite') $lang->admin->menuList->feature['menuOrder']['15'] = 'project'; } + +if($config->inQuickon) +{ + $lang->admin->menuList->system['subMenu']['backup'] = array('link' => "{$lang->backup->common}|system|browsebackup|", 'alias' => 'restorebackup'); +} diff --git a/module/cne/model.php b/module/cne/model.php index 81d5b68774..493286c8c1 100644 --- a/module/cne/model.php +++ b/module/cne/model.php @@ -1202,4 +1202,85 @@ class cneModel extends model return $this->error; } + + /** + * 获取备份平台列表。 + * Get backup platform list. + * + * @access public + * @return object + */ + public function getBackupPlatformList(): object + { + $apiUrl = "/api/cne/platform/backups"; + return $this->apiGet($apiUrl, array(), $this->config->CNE->api->headers); + } + + /** + * 备份平台和应用。 + * Backup platform and apps. + * + * @param array $apps + * @access public + * @return object + */ + public function backupPlatform(array $apps = array()): object + { + $apiParams = new stdclass(); + $apiParams->apps = $apps; + + $apiUrl = "/api/cne/platform/backup"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * 获取备份平台状态。 + * Get backup platfrom status. + * + * @param string $name + * @access public + * @return object + */ + public function backupPlatformStatus(string $name): object + { + $apiParams = new stdclass(); + $apiParams->name = $name; + + $apiUrl = "/api/cne/platform/backup/status"; + return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * 还原平台和应用。 + * Restroe platform and apps. + * + * @param array $apps + * @access public + * @return object + */ + public function restorePlatform(string $name): object + { + $apiParams = new stdclass(); + $apiParams->backup_set_name = $name; + + $apiUrl = "/api/cne/platform/restore"; + return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); + } + + /** + * 获取备份平台状态。 + * Get backup platfrom status. + * + * @param string $name + * @access public + * @return object + */ + public function restorePlatformStatus(string $name): object + { + $apiParams = new stdclass(); + $apiParams->name = $name; + + $apiUrl = "/api/cne/platform/restore/status"; + return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); + } } diff --git a/module/sonarqube/control.php b/module/sonarqube/control.php index 3dcb9b5d4a..dae6dd7320 100644 --- a/module/sonarqube/control.php +++ b/module/sonarqube/control.php @@ -140,7 +140,7 @@ class sonarqube extends control ->skipSpecial('url,token,account,password') ->remove('token,appType') ->get(); - $this->checkToken($sonarqube); + $this->checkToken($sonarqube, 0); $sonarqubeID = $this->loadModel('pipeline')->create($sonarqube); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -160,9 +160,8 @@ class sonarqube extends control * @access protected * @return void */ - protected function checkToken(int $sonarqubeID) + protected function checkToken(object $sonarqube, int $sonarqubeID = 0) { - $sonarqube = fixer::input('post')->trim('url,token,account,password')->get(); $this->dao->update('sonarqube')->data($sonarqube) ->batchCheck(empty($sonarqubeID) ? $this->config->sonarqube->create->requiredFields : $this->config->sonarqube->edit->requiredFields, 'notempty') ->batchCheck("url", 'URL'); diff --git a/module/space/control.php b/module/space/control.php index c83c86a240..0c6d20762a 100644 --- a/module/space/control.php +++ b/module/space/control.php @@ -106,10 +106,13 @@ class space extends control $this->app->loadLang('jenkins'); $this->loadModel('cne'); - $pagedApps = $this->loadModel('store')->searchApps('', '', array(), 1, 10000); - $apps = array(); + $pagedApps = $this->loadModel('store')->searchApps('', '', array(), 1, 10000); + $apps = array(); + $defaultApp = ''; foreach($pagedApps->apps as $app) { + if(!$appID and $app->alias == 'GitLab') $defaultApp = $app->id; + $apps[$app->id] = $app->alias; } @@ -119,6 +122,7 @@ class space extends control $this->view->apps = $apps; $this->view->appID = $appID; + $this->view->defaultApp = $defaultApp; $this->view->pgList = $pgList; $this->view->mysqlList = $mysqlList; $this->view->versionList = $versionList; diff --git a/module/space/js/createapplication.ui.js b/module/space/js/createapplication.ui.js index 2a50b7f23f..a0c90ffd43 100644 --- a/module/space/js/createapplication.ui.js +++ b/module/space/js/createapplication.ui.js @@ -70,28 +70,29 @@ function onChangeAppType(event) } } -function onChangeStoreAppType() +function onChangeStoreAppType(event) { - var storeApp = $('[name=storeAppType]').val(); - if(!storeApp) + if(typeof(event) == 'undefined') { - for(id in apps) - { - storeApp = id; - break; - } + var storeApp = defaultApp; } + else + { + var storeApp = $('[name=storeAppType]').val(); + } + $('#createStoreAppForm').attr('action', $.createLink('instance', 'install', 'appID=' + storeApp)); var externalApps = ['GitLab', 'Gitea', 'Gogs', 'Jenkins', 'SonarQube']; var storeAppName = apps[storeApp]; + if(externalApps.indexOf(storeAppName) !== -1) { - $('#storetypeexternal').prop('disabled', false); + $('#createStoreAppForm input[name=type][value=external]').prop('disabled', false); } else { - $('#storetypeexternal').prop('disabled', true); + $('#createStoreAppForm input[name=type][value=external]').prop('disabled', true); } toggleLoading('#app_version', true); diff --git a/module/space/lang/en.php b/module/space/lang/en.php index c241b37134..eaef92d3f3 100644 --- a/module/space/lang/en.php +++ b/module/space/lang/en.php @@ -1,9 +1,27 @@ space->status = 'Status'; +$lang->space->noApps = 'No service'; +$lang->space->defaultSpace = 'Default space'; +$lang->space->systemSpace = 'System space'; +$lang->space->searchInstance = 'Search Services'; +$lang->space->upgrade = 'Upgrade'; +$lang->space->install = 'Add an application'; +$lang->space->createdBy = 'Creator'; +$lang->space->createdAt = 'Creation time'; $lang->space->handConfig = 'Manual configuration'; $lang->space->addType = 'Add method'; +$lang->space->instanceType = 'Instance type'; -$lang->space->appType['Gitlab'] = 'Gitlab'; +$lang->space->byList = 'List'; +$lang->space->byCard = 'Card'; + +$lang->space->featureBar['browse']['all'] = 'All'; +$lang->space->featureBar['browse']['running'] = 'Running'; +$lang->space->featureBar['browse']['stopped'] = 'Stopped'; +$lang->space->featureBar['browse']['abnormal'] = 'Abnormal'; + +$lang->space->appType['GitLab'] = 'GitLab'; $lang->space->appType['Gitea'] = 'Gitea'; $lang->space->appType['Gogs'] = 'Gogs'; $lang->space->appType['Jenkins'] = 'Jenkins'; -$lang->space->appType['Sonarqube'] = 'Sonarqube'; +$lang->space->appType['SonarQube'] = 'SonarQube'; diff --git a/module/space/lang/zh-cn.php b/module/space/lang/zh-cn.php index 3ecf410f58..34a74b3181 100644 --- a/module/space/lang/zh-cn.php +++ b/module/space/lang/zh-cn.php @@ -19,13 +19,12 @@ $lang->space->byList = '列表'; $lang->space->byCard = '卡片'; $lang->space->featureBar['browse']['all'] = '全部'; -//$lang->space->filterList['toBeUpdated'] = '待更新'; $lang->space->featureBar['browse']['running'] = '运行中'; $lang->space->featureBar['browse']['stopped'] = '已停止'; $lang->space->featureBar['browse']['abnormal'] = '异常'; -$lang->space->appType['Gitlab'] = 'Gitlab'; +$lang->space->appType['GitLab'] = 'GitLab'; $lang->space->appType['Gitea'] = 'Gitea'; $lang->space->appType['Gogs'] = 'Gogs'; $lang->space->appType['Jenkins'] = 'Jenkins'; -$lang->space->appType['Sonarqube'] = 'Sonarqube'; +$lang->space->appType['SonarQube'] = 'SonarQube'; diff --git a/module/space/ui/createapplication.html.php b/module/space/ui/createapplication.html.php index 48d19cf093..c2720c3a95 100644 --- a/module/space/ui/createapplication.html.php +++ b/module/space/ui/createapplication.html.php @@ -19,6 +19,7 @@ jsVar('jenkinsPasswordTips', $lang->jenkins->tips); jsVar('apps', $apps); jsVar('mysqlList', $mysqlList); jsVar('pgList', $pgList); +jsVar('defaultApp', $defaultApp); $showVersion = getenv('ALLOW_SELECT_VERSION') && (strtolower(getenv('ALLOW_SELECT_VERSION')) == 'true' || strtolower(getenv('ALLOW_SELECT_VERSION')) == '1'); $dbTypeItems = array(); @@ -26,82 +27,7 @@ foreach($lang->instance->dbTypes as $type => $db) $dbTypeItems[] = array('text' formPanel ( - setClass('externalPanel' . (!$appID ? '' : ' hidden')), - set::id('createAppForm'), - set::title($lang->space->install), - set::url($this->createLink('gitlab', 'create')), - formGroup - ( - set::width('1/2'), - set::label($lang->app->common), - set::name('appType'), - set::items($lang->space->appType), - set::required(true), - on::change('onChangeAppType'), - ), - formGroup - ( - set::label($lang->space->addType), - set::name('type'), - set::value('external'), - set::control('radioListInline'), - set::items(array(array('text' => $lang->store->common, 'value' => 'store'), array('text' => $lang->space->handConfig, 'value' => 'external'))), - set::required(true), - on::change('onChangeType'), - ), - formGroup - ( - set::width('1/2'), - set::label($lang->gitlab->name), - set::name('name'), - set::required(true), - ), - formGroup - ( - set::width('2/3'), - set::label($lang->gitlab->url), - set::name('url'), - set::required(true), - set::placeholder($lang->gitlab->placeholder->url) - ), - formRow - ( - setClass('jenkins sonarqube hidden'), - formGroup - ( - set::width('1/2'), - set::label($lang->user->account), - set::name('account'), - set::required(true), - ), - ), - formRow - ( - setClass('token'), - formGroup - ( - set::width('1/2'), - set::label($lang->gitlab->token), - set::name('token'), - set::placeholder($lang->gitlab->placeholder->token), - set::required(true), - ), - ), - formRow - ( - setClass('jenkins sonarqube password hidden'), - formGroup - ( - set::width('1/2'), - set::label($lang->user->password), - set::name('password'), - ), - ), -); - -formPanel -( - setClass('storePanel' . ($appID ? '' : ' hidden')), + setClass('storePanel'), set::id('createStoreAppForm'), set::title($lang->space->install), $appID ? set::submitBtnText($lang->instance->install) : null, @@ -111,7 +37,7 @@ formPanel setStyle('display', $appID ? 'block' : 'none'), formGroup ( - set::width('1/2'), + set::width('2/3'), set::label($lang->instance->name), set::name('customName'), set::control('input'), @@ -124,11 +50,11 @@ formPanel setStyle('display', $appID ? 'none' : 'block'), formGroup ( - set::width('1/2'), + set::width('2/3'), set::label($lang->app->common), set::name('storeAppType'), set::items($apps), - set::value($appID), + set::value($appID ? $appID : $defaultApp), set::disabled(!!$appID), set::required(true), on::change('onChangeStoreAppType'), @@ -151,7 +77,7 @@ formPanel ), $showVersion ? formGroup ( - set::width('1/2'), + set::width('2/3'), set::label($lang->instance->version), set::name('version'), set::required(true), @@ -159,7 +85,7 @@ formPanel set::items($versionList) ) : formGroup ( - set::width('1/2'), + set::width('2/3'), set::label($lang->instance->version), set::name('app_version'), set::required(true), @@ -174,7 +100,7 @@ formPanel ( formGroup ( - set::width('1/2'), + set::width('2/3'), set::label($lang->instance->domain), set::required(true), inputGroup @@ -216,7 +142,7 @@ formPanel setClass('dbType dbService'), formGroup ( - set::width('1/2'), + set::width('2/3'), set::label($lang->space->instanceType), set::name('dbService'), set::items(array()), @@ -225,4 +151,79 @@ formPanel ), ); +formPanel +( + setClass('externalPanel hidden'), + set::id('createAppForm'), + set::title($lang->space->install), + set::url($this->createLink('gitlab', 'create')), + formGroup + ( + set::width('2/3'), + set::label($lang->app->common), + set::name('appType'), + set::items($lang->space->appType), + set::required(true), + on::change('onChangeAppType'), + ), + formGroup + ( + set::label($lang->space->addType), + set::name('type'), + set::value('external'), + set::control('radioListInline'), + set::items(array(array('text' => $lang->store->common, 'value' => 'store'), array('text' => $lang->space->handConfig, 'value' => 'external'))), + set::required(true), + on::change('onChangeType'), + ), + formGroup + ( + set::width('2/3'), + set::label($lang->gitlab->name), + set::name('name'), + set::required(true), + ), + formGroup + ( + set::width('2/3'), + set::label($lang->gitlab->url), + set::name('url'), + set::required(true), + set::placeholder($lang->gitlab->placeholder->url) + ), + formRow + ( + setClass('jenkins sonarqube hidden'), + formGroup + ( + set::width('2/3'), + set::label($lang->user->account), + set::name('account'), + set::required(true), + ), + ), + formRow + ( + setClass('token'), + formGroup + ( + set::width('2/3'), + set::label($lang->gitlab->token), + set::name('token'), + set::placeholder($lang->gitlab->placeholder->token), + set::required(true), + ), + ), + formRow + ( + setClass('jenkins sonarqube password hidden'), + formGroup + ( + set::width('2/3'), + set::label($lang->user->password), + set::name('password'), + ), + ), +); + render(); diff --git a/module/system/config/dtable.php b/module/system/config/dtable.php index d1b47252f1..57b1135c94 100644 --- a/module/system/config/dtable.php +++ b/module/system/config/dtable.php @@ -31,9 +31,13 @@ $config->system->dtable->backup = new stdclass(); $config->system->dtable->backup->fieldList['time']['title'] = $lang->backup->time; $config->system->dtable->backup->fieldList['time']['type'] = 'datetime'; -$config->system->dtable->backup->fieldList['backupPerson']['title'] = $lang->system->backup->backupPerson; - $config->system->dtable->backup->fieldList['type']['title'] = $lang->system->backup->type; +$config->system->dtable->backup->fieldList['type']['map'] = $lang->system->backup->typeList; + +$config->system->dtable->backup->fieldList['status']['title'] = $lang->backup->status; + +$config->system->dtable->backup->fieldList['comment']['title'] = $lang->comment; +$config->system->dtable->backup->fieldList['comment']['type'] = 'html'; $config->system->dtable->backup->fieldList['actions']['name'] = 'actions'; $config->system->dtable->backup->fieldList['actions']['title'] = $lang->actions; @@ -42,10 +46,10 @@ $config->system->dtable->backup->fieldList['actions']['menu'] = array('restore' $config->system->dtable->backup->fieldList['actions']['list']['restore']['icon'] = 'history'; $config->system->dtable->backup->fieldList['actions']['list']['restore']['hint'] = $lang->backup->restore; -$config->system->dtable->backup->fieldList['actions']['list']['restore']['url'] = array('module' => 'backup', 'method' => 'restore', 'params' => 'time={time}'); -$config->system->dtable->backup->fieldList['actions']['list']['restore']['data-confirm'] = $lang->system->backup->confirmDelete; +$config->system->dtable->backup->fieldList['actions']['list']['restore']['url'] = array('module' => 'system', 'method' => 'restoreBackup', 'params' => 'name={name}'); +$config->system->dtable->backup->fieldList['actions']['list']['restore']['data-confirm'] = $lang->system->backup->confirmRestore; $config->system->dtable->backup->fieldList['actions']['list']['delete']['icon'] = 'trash'; $config->system->dtable->backup->fieldList['actions']['list']['delete']['hint'] = $lang->delete; -$config->system->dtable->backup->fieldList['actions']['list']['delete']['url'] = array('module' => 'backup', 'method' => 'delete', 'params' => 'time={time}'); -$config->system->dtable->backup->fieldList['actions']['list']['delete']['data-confirm'] = $lang->system->backup->confirmRestore; +$config->system->dtable->backup->fieldList['actions']['list']['delete']['url'] = array('module' => 'system', 'method' => 'deleteBackup', 'params' => 'name={name}'); +$config->system->dtable->backup->fieldList['actions']['list']['delete']['data-confirm'] = $lang->system->backup->confirmDelete; diff --git a/module/system/control.php b/module/system/control.php index 9ffe0cb106..e8913b78d9 100644 --- a/module/system/control.php +++ b/module/system/control.php @@ -572,31 +572,44 @@ class system extends control $this->display(); } + /** + * 平台备份列表。 + * Browse platform backup. + * + * @access public + * @return viod + */ public function browseBackup() { + $this->loadModel('repo'); $backups = array(); - if(empty($this->view->error)) + + $actions = $this->loadModel('action')->getList('platformbackup', 0); + foreach($actions as $id => $action) { - $sqlFiles = glob("{$this->backupPath}*.sql*"); - if(!empty($sqlFiles)) + if($action->action != 'backupcommented') { - foreach($sqlFiles as $file) - { - $fileName = basename($file); - $backupFile = new stdclass(); - $backupFile->time = filemtime($file); - $backupFile->name = substr($fileName, 0, strpos($fileName, '.')); - $backupFile->sqlSummary = $this->system->getSQLSummary($file); - $backupFile->files[$file] = $this->backup->getBackupSummary($file); + unset($actions[$id]); + continue; + } - $fileBackup = $this->backup->getBackupFile($backupFile->name, 'file'); - if($fileBackup) $backupFile->files[$fileBackup] = $this->backup->getBackupSummary($fileBackup); + $actions[$action->extra] = $action; + unset($actions[$id]); + } - $codeBackup = $this->backup->getBackupFile($backupFile->name, 'code'); - if($codeBackup) $backupFile->files[$codeBackup] = $this->backup->getBackupSummary($codeBackup); + $result = $this->loadModel('cne')->getBackupPlatformList(); + if($result && $result->data) + { + foreach($result->data as $data) + { + $backup = new stdclass(); + $backup->time = date("Y-m-d H:i:s", $data->create_time); + $backup->status = zget($this->lang->system->backup->statusList, $data->status); + $backup->name = $this->repo->encodePath($data->name); + $backup->type = (!empty($actions[$data->name]) && $actions[$data->name]->objectType == 'platformbackup') ? 'manual' : ''; + $backup->comment = !empty($actions[$data->name]) ? nl2br($actions[$data->name]->comment) : ''; - $backups[$backupFile->name] = $backupFile; - } + $backups[$data->create_time] = $backup; } } krsort($backups); @@ -607,6 +620,124 @@ class system extends control $this->display(); } + /** + * Backup platform and apps. + * + * @access public + * @return viod + */ + public function backupPlatform() + { + if($_POST) + { + session_write_close(); + + $space = $this->loadModel('space')->defaultSpace($this->app->user->account); + $instances = $this->space->getSpaceInstances($space->id); + $apps = array(); + foreach($instances as $instance) + { + $app = new stdclass(); + $app->name = $instance->k8name; + $app->namespace = $space->k8space; + + $apps[] = $app; + } + + $result = $this->loadModel('cne')->backupPlatform($apps); + if($result && $result->code == 200) + { + $this->loadModel('action')->create('platformBackup', '0', 'backupCommented', $this->post->comment, $result->data->name); + return $this->send(array('result' => 'success', 'name' => $result->data->name)); + } + else + { + return $this->send(array('result' => 'failed', 'message' => $result->message)); + } + } + + $this->display(); + } + + /** + * 还原平台备份。 + * Restore platform backup. + * + * @param string $backupName + * @access public + * @return viod + */ + public function restoreBackup(string $backupName) + { + $backupName = $this->loadModel('repo')->decodePath($backupName); + + $error = ''; + $result = $this->loadModel('cne')->restorePlatform($backupName); + if($result && $result->code == 200) + { + $restoreName = $result->data->name; + $this->loadModel('action')->create('platformBackup', '0', 'restore', '', $restoreName); + } + else + { + $error = $result->message; + } + + $this->view->error = $error; + $this->view->restoreName = $restoreName; + $this->display(); + } + + /** + * Ajax 获取备份进度。 + * Ajax get backup progress. + * + * @access public + * @return viod + */ + public function ajaxGetBackupProgress() + { + session_write_close(); + + $result = $this->loadModel('cne')->backupPlatformStatus($this->post->name); + if($result && $result->code == 200) + { + $status = $result->data->status; + if($status == 'completed') return $this->send(array('result' => 'success', 'message' => $this->lang->backup->success->backup, 'closeModal' => true, 'load' => inlink('browseBackup'))); + if($status == 'pending' || $status == 'inprogress') return $this->send(array('result' => 'progress', 'text' => sprintf($this->lang->system->backup->progress, $result->data->completed, $result->data->total))); + if($status == 'failed') return $this->send(array('result' => 'failed', 'message' => $this->lang->system->backup->error->backupFail, 'closeModal' => true)); + } + else + { + return $this->send(array('result' => 'failed', 'message' => $result->message, 'closeModal' => true)); + } + } + + /** + * Ajax 获取还原进度。 + * Ajax get restore progress. + * + * @access public + * @return viod + */ + public function ajaxGetRestoreProgress() + { + session_write_close(); + + $result = $this->loadModel('cne')->restorePlatformStatus($this->post->name); + if($result && $result->code == 200) + { + $status = $result->data->status; + if($status == 'completed') return $this->send(array('result' => 'success', 'message' => $this->lang->backup->success->restore, 'load' => inlink('browseBackup'))); + if($status == 'pending' || $status == 'inprogress') return $this->send(array('result' => 'progress', 'text' => sprintf($this->lang->system->backup->progressStore, $result->data->completed, $result->data->total))); + if($status == 'failed') return $this->send(array('result' => 'failed', 'message' => $this->lang->system->backup->error->backupFail, 'load' => inlink('browseBackup'))); + } + else + { + return $this->send(array('result' => 'failed', 'message' => $result->message, 'load' => inlink('browseBackup'))); + } + } + /** * Verify SMTP account by ajax. * diff --git a/module/system/js/backupplatform.ui.js b/module/system/js/backupplatform.ui.js new file mode 100644 index 0000000000..23b65c3aba --- /dev/null +++ b/module/system/js/backupplatform.ui.js @@ -0,0 +1,57 @@ +var backupInterval; +var backupName; + +/** + * Start backup. + * + * @access public + * @return viod + */ +function startBackup() +{ + const form = new FormData($("#backupForm")[0]); + + $.ajaxSubmit({ + url: $.createLink('system', 'backupPlatform'), + data: form, + onComplete: function(response) + { + if(response.result == 'success') + { + $('.modal-content .panel-body').html(waitting); + backupName = response.name; + backupInterval = setInterval(checkBackup, 2000); + } + else + { + zui.Modal.alert(response.message); + } + }, + }); +} + +/** + * Check backup progress. + * + * @access public + * @return viod + */ +function checkBackup() +{ + $.ajaxSubmit({ + url: $.createLink('system', 'ajaxGetBackupProgress'), + data: {'name': backupName}, + onComplete: function(response) + { + if(response.result == 'progress') + { + $('.modal-content .panel-body').html(response.text); + } + else + { + clearInterval(backupInterval); + if(response.result == 'failed') zui.Modal.alert(response.message); + } + }, + }); +} diff --git a/module/system/js/restorebackup.ui.js b/module/system/js/restorebackup.ui.js new file mode 100644 index 0000000000..5d0d28136f --- /dev/null +++ b/module/system/js/restorebackup.ui.js @@ -0,0 +1,35 @@ +/** + * Check restore progress. + * + * @access public + * @return viod + */ +function checkRestore() +{ + $.ajaxSubmit({ + url: $.createLink('system', 'ajaxGetRestoreProgress'), + data: {'name': restoreName}, + onComplete: function(response) + { + if(response.result == 'progress') + { + $('div.restoreProgress').html(response.text); + } + else + { + clearInterval(restoreInterval); + if(response.result == 'failed') zui.Modal.alert(response.message); + } + }, + }); +} + +if(error) +{ + zui.Modal.alert(error); + openUrl($.createLink('system', 'browseBackup')); +} +else +{ + var restoreInterval = setInterval(checkRestore, 2000); +} diff --git a/module/system/lang/en.php b/module/system/lang/en.php index 9901ec3342..94d6058569 100644 --- a/module/system/lang/en.php +++ b/module/system/lang/en.php @@ -210,6 +210,11 @@ $lang->system->backup->rollback = 'Rollback'; $lang->system->backup->restart = 'Restart'; $lang->system->backup->delete = 'Delte'; +$lang->system->backup->statusList['pending'] = 'Waiting'; +$lang->system->backup->statusList['inprogress'] = 'In progress'; +$lang->system->backup->statusList['completed'] = 'Compelete'; +$lang->system->backup->statusList['failed'] = 'Fail'; + $lang->system->backup->restoreProgress['doing'] = 'Doing'; $lang->system->backup->restoreProgress['done'] = 'Done'; @@ -217,12 +222,14 @@ $lang->system->backup->typeList['manual'] = 'Manual backup'; $lang->system->backup->typeList['upgrade'] = 'Automatic backup before upgrade'; $lang->system->backup->typeList['restore'] = 'Automatic backup before rollback'; -$lang->system->backup->waitting = 'In progress,please wait...'; +$lang->system->backup->waitting = 'Backup is in progress, please wait...'; +$lang->system->backup->waittingStore = 'Restoring app data, please wait...'; +$lang->system->backup->progress = 'Backup in progress(%d/%d)'; $lang->system->backup->progressSQL = 'In backup,%s has been backed up'; $lang->system->backup->progressAttach = 'There are a total of %s files in the backup, and %s files have already been backed up'; $lang->system->backup->progressCode = 'There are a total of %s files in the backup, and %s files have already been backed up'; $lang->system->backup->confirmDelete = 'Do you want to delte the backup'; -$lang->system->backup->confirmRestore = 'Please confirm whether to roallback?'; +$lang->system->backup->confirmRestore = 'A restart is required during the platform restore process, which will cause all your current operations to be interrupted and cannot be restored. Are you sure you want to continue?'; $lang->system->backup->holdDays = 'Backup has been retained for the last %s days'; $lang->system->backup->copiedFail = 'Files that failed to copy:'; $lang->system->backup->restoreTip = 'The restore function only restores the database.'; @@ -239,7 +246,8 @@ $lang->system->backup->success->upgrade = 'Upgrade successful!'; $lang->system->backup->success->degrade = 'Successfully downgraded!'; $lang->system->backup->error = new stdclass(); - +$lang->system->backup->error->backupFail = "Backup failed!"; +$lang->system->backup->error->restoreFail = "Restore failed!"; $lang->system->backup->error->upgradeFail = "Upgrade failed!"; $lang->system->backup->error->upgradeOvertime = "Upgrade timed out!"; $lang->system->backup->error->degradeFail = "Downgrade failed!"; diff --git a/module/system/lang/zh-cn.php b/module/system/lang/zh-cn.php index be6a14cc69..6116c185de 100644 --- a/module/system/lang/zh-cn.php +++ b/module/system/lang/zh-cn.php @@ -212,6 +212,11 @@ $lang->system->backup->rollback = '回滚'; $lang->system->backup->restart = '重启'; $lang->system->backup->delete = '删除'; +$lang->system->backup->statusList['pending'] = '等待中'; +$lang->system->backup->statusList['inprogress'] = '进行中'; +$lang->system->backup->statusList['completed'] = '完成'; +$lang->system->backup->statusList['failed'] = '失败'; + $lang->system->backup->restoreProgress['doing'] = '进行中'; $lang->system->backup->restoreProgress['done'] = '完成'; @@ -219,12 +224,15 @@ $lang->system->backup->typeList['manual'] = '手动备份'; $lang->system->backup->typeList['upgrade'] = '升级前自动备份'; $lang->system->backup->typeList['restore'] = '回滚前自动备份'; -$lang->system->backup->waitting = '正在进行中,请稍候...'; +$lang->system->backup->waitting = '备份正在进行中,请稍候...'; +$lang->system->backup->waittingStore = '正在还原应用数据,请稍候...'; +$lang->system->backup->progress = '备份中,进度(%d/%d)'; +$lang->system->backup->progressStore = '还原中,进度(%d/%d)'; $lang->system->backup->progressSQL = '备份中,已备份%s'; $lang->system->backup->progressAttach = '备份中,共有%s个文件,已经备份%s个'; $lang->system->backup->progressCode = '代码备份中,共有%s个文件,已经备份%s个'; $lang->system->backup->confirmDelete = '是否删除该备份?'; -$lang->system->backup->confirmRestore = '请确认是否回滚?'; +$lang->system->backup->confirmRestore = '平台还原过程中需要重启,这将导致您当前的所有操作中断并且无法恢复,您确定要继续吗?'; $lang->system->backup->holdDays = '备份保留最近 %s 天'; $lang->system->backup->copiedFail = '复制失败的文件:'; $lang->system->backup->restoreTip = '还原功能只还原数据库。'; @@ -242,6 +250,8 @@ $lang->system->backup->success->degrade = '降级成功!'; $lang->system->backup->error = new stdclass(); +$lang->system->backup->error->backupFail = "备份失败!"; +$lang->system->backup->error->restoreFail = "还原失败!"; $lang->system->backup->error->upgradeFail = "升级失败!"; $lang->system->backup->error->upgradeOvertime = "升级超时!"; $lang->system->backup->error->degradeFail = "降级失败!"; diff --git a/module/system/ui/backupplatform.html.php b/module/system/ui/backupplatform.html.php new file mode 100644 index 0000000000..909f087609 --- /dev/null +++ b/module/system/ui/backupplatform.html.php @@ -0,0 +1,33 @@ + + * @package system + * @link https://www.zentao.net + */ +namespace zin; + +jsVar('waitting', $lang->system->backup->waitting); + +modalHeader(set::title($lang->system->backup->backup)); +formPanel +( + on::click('#startBackup', 'startBackup'), + set::id('backupForm'), + formGroup + ( + set::label($lang->comment), + set::name('comment'), + set::control('textarea'), + set::rows('6'), + ), + set::actions(array + ( + array('text' => $lang->confirm, 'id' => 'startBackup', 'class' => 'primary'), + )), +); + +render(); diff --git a/module/system/ui/browsebackup.html.php b/module/system/ui/browsebackup.html.php index ab7cf43811..1e3466d4a5 100644 --- a/module/system/ui/browsebackup.html.php +++ b/module/system/ui/browsebackup.html.php @@ -10,18 +10,24 @@ declare(strict_types=1); */ namespace zin; -foreach($backups as $backup) -{ - $backup->backupPerson = isset($backup->sqlSummary['account']) ? $backup->sqlSummary['account'] : ''; - if(empty($backup->sqlSummary['backupType'])) $backup->sqlSummary['backupType'] = ''; - $backup->type = $backup->sqlSummary['backupType']; -} $backups = initTableData($backups, $config->system->dtable->backup->fieldList, $this->system); panel ( set::size('lg'), - set::title($lang->system->backup->systemInfo), + set::title($lang->backup->history), + to::headingActions + ( + a + ( + setClass('btn primary'), + icon('copy'), + set::href($this->createLink('system', 'backupPlatform')), + set::target('hiddenwin'), + $lang->backup->backup, + set('data-toggle', 'modal'), + ), + ), div ( setStyle('width', '66.6%'), diff --git a/module/system/ui/restorebackup.html.php b/module/system/ui/restorebackup.html.php new file mode 100644 index 0000000000..e46da2c04c --- /dev/null +++ b/module/system/ui/restorebackup.html.php @@ -0,0 +1,23 @@ + + * @package mr + * @link https://www.zentao.net + */ +namespace zin; + +jsVar('restoreName', $restoreName); +jsVar('error', $error); + +div +( + setClass('restoreProgress text-3xl'), + $lang->system->backup->waittingStore, +); + +render(); +