model.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. <?php
  2. /**
  3. * The model file of system module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL (http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Jianhua Wang <wangjianhua@easycorp.ltd>
  8. * @package system
  9. * @version $Id$
  10. * @link https://www.zentao.net
  11. * @property cneModel $cne
  12. */
  13. class systemModel extends model
  14. {
  15. /**
  16. * 获取应用列表。
  17. * Get app list.
  18. *
  19. * @param int $productID
  20. * @param string $status
  21. * @param string $orderBy
  22. * @param object $pager
  23. * @access public
  24. * @return array
  25. */
  26. public function getList($productID, $status = 'active', $orderBy = 'id_desc', $pager = null)
  27. {
  28. if(common::isTutorialMode()) return $this->loadModel('tutorial')->getSystemList();
  29. return $this->dao->select('*')->from(TABLE_SYSTEM)
  30. ->where('deleted')->eq('0')
  31. ->andWhere('product')->eq($productID)
  32. ->beginIF($status && $status != 'all')->andWhere('status')->eq($status)->fi()
  33. ->orderBy($orderBy)
  34. ->page($pager)
  35. ->fetchAll('id', false);
  36. }
  37. /**
  38. * 获取应用键值对。
  39. * Get app pairs.
  40. *
  41. * @param int $productID
  42. * @param string $integrated
  43. * @param string $status
  44. * @access public
  45. * @return array
  46. */
  47. public function getPairs($productID = 0, $integrated = '', $status = '')
  48. {
  49. if(common::isTutorialMode()) return $this->loadModel('tutorial')->getSystemPairs();
  50. return $this->dao->select('id, name')->from(TABLE_SYSTEM)
  51. ->where('deleted')->eq('0')
  52. ->beginIF($productID)->andWhere('product')->eq($productID)->fi()
  53. ->beginIF($status)->andWhere('status')->eq($status)->fi()
  54. ->beginIF($integrated !== '')->andWhere('integrated')->eq($integrated)->fi()
  55. ->orderBy('id DESC')
  56. ->fetchPairs('id', 'name');
  57. }
  58. /**
  59. * 根据产品ids列表获取状态正常的非集成应用键值对。
  60. * @param int[] $products
  61. * @return array
  62. */
  63. public function getPairsByProducts($products)
  64. {
  65. $products = array_values(array_filter($products));
  66. return $this->dao->select('id, name')->from(TABLE_SYSTEM)
  67. ->where('deleted')->eq('0')
  68. ->beginIF(!empty($products))->andWhere('product')->in($products)->fi()
  69. ->andWhere('status')->eq('active')
  70. ->andWhere('integrated')->eq(0)
  71. ->orderBy('id DESC')
  72. ->fetchPairs('id', 'name');
  73. }
  74. /**
  75. * 根据ID列表获取应用。
  76. * Get apps by id list.
  77. *
  78. * @param array $idList
  79. * @access public
  80. * @return array
  81. */
  82. public function getByIdList($idList)
  83. {
  84. return $this->dao->select('*')->from(TABLE_SYSTEM)
  85. ->where('deleted')->eq('0')
  86. ->andWhere('id')->in($idList)
  87. ->fetchAll('id');
  88. }
  89. /**
  90. * 根据应用ID列表获取产品ID列表。
  91. * Get product id list by system id list.
  92. *
  93. * @param array $systemIDs
  94. * @return array
  95. */
  96. public function getProductListBySystemIds($systemIDs)
  97. {
  98. return $this->dao->select('t1.id,t1.name as appName,t1.product,t2.name as productName')
  99. ->from(TABLE_SYSTEM)->alias('t1')
  100. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id')
  101. ->where('t1.deleted')->eq('0')
  102. ->andWhere('t1.id')->in(implode(',', $systemIDs))
  103. ->fetchAll('id');
  104. }
  105. /**
  106. * 创建应用。
  107. * Create an app.
  108. *
  109. * @param object $formData
  110. * @access public
  111. * @return bool|int
  112. */
  113. public function create($formData)
  114. {
  115. $this->dao->insert(TABLE_SYSTEM)->data($formData)
  116. ->check('name', 'unique')
  117. ->batchCheck($this->config->system->create->requiredFields, 'notempty')
  118. ->autoCheck()
  119. ->exec();
  120. if(dao::isError())
  121. {
  122. if($this->app->rawModule != 'system' && !empty(dao::$errors['name']))
  123. {
  124. dao::$errors['systemName'] = dao::$errors['name'];
  125. unset(dao::$errors['name']);
  126. }
  127. return false;
  128. }
  129. $systemID = $this->dao->lastInsertID();
  130. $this->loadModel('action')->create('system', $systemID, 'created', '', '', zget($formData, 'createdBy', $this->app->user->account));
  131. return $systemID;
  132. }
  133. /**
  134. * 编辑应用。
  135. * Edit an app.
  136. *
  137. * @param int $id
  138. * @param object $formData
  139. * @param string $type
  140. * @access public
  141. * @return bool
  142. */
  143. public function update($id, $formData, $type = 'edit')
  144. {
  145. $oldSystem = $this->fetchByID($id);
  146. $change = common::createChanges($oldSystem, $formData);
  147. if(empty($change)) return true;
  148. $this->dao->update(TABLE_SYSTEM)->data($formData)
  149. ->check('name', 'unique', '`id` != ' . $id)
  150. ->autoCheck()
  151. ->beginIF($type == 'edit')->batchCheck($this->config->system->edit->requiredFields, 'notempty')->fi()
  152. ->where('id')->eq($id)
  153. ->exec();
  154. if(dao::isError()) return false;
  155. $actionType = $type == 'edit' ? 'edited' : $type;
  156. $actionID = $this->loadModel('action')->create('system', $id, $actionType);
  157. if($actionID) $this->action->logHistory($actionID, $change);
  158. return !dao::isError();
  159. }
  160. /**
  161. * 获取自定义的域名设置。
  162. * Get customized domain settings.
  163. *
  164. * @access public
  165. * @return object
  166. */
  167. public function getDomainSettings()
  168. {
  169. $this->loadModel('setting');
  170. $settings = new stdclass;
  171. $settings->customDomain = $this->setting->getItem('owner=system&module=common&section=domain&key=customDomain');
  172. $settings->https = $this->setting->getItem('owner=system&module=common&section=domain&key=https');
  173. $settings->certPem = '';
  174. $settings->certKey = '';
  175. return $settings;
  176. }
  177. /**
  178. * 保存自定义的域名设置。
  179. * Save customized domain settings.
  180. *
  181. * @param object $setting
  182. * @access public
  183. * @return void
  184. * @param object $settings
  185. */
  186. public function saveDomainSettings($settings)
  187. {
  188. $this->loadModel('setting');
  189. $this->dao->from('system')->data($settings)
  190. ->check('customDomain', 'notempty')
  191. ->checkIf($settings->https == 'true', 'certPem', 'notempty')
  192. ->checkIf($settings->https == 'true', 'certKey', 'notempty');
  193. if(dao::isError()) return;
  194. if(!validater::checkREG($settings->customDomain, '/^((?!-)[a-z0-9-]{1,63}(?<!-)\\.)+[a-z]{2,6}$/'))
  195. {
  196. dao::$errors[] = $this->lang->system->errors->invalidDomain;
  197. return;
  198. }
  199. /* Upload Certificate to CNE. */
  200. if($settings->https == 'true')
  201. {
  202. $cert = new stdclass;
  203. $cert->name = 'tls-' . str_replace('.', '-', $settings->customDomain);
  204. $cert->certificate_pem = $settings->certPem;
  205. $cert->private_key_pem = $settings->certKey;
  206. $certResult = $this->loadModel('cne')->uploadCert($cert);
  207. if($certResult->code != 200)
  208. {
  209. dao::$errors[] = $certResult->message;
  210. return;
  211. }
  212. }
  213. if(stripos($settings->customDomain, 'haogs.cn') !== false) dao::$errors[] = $this->lang->system->errors->forbiddenOriginalDomain;
  214. if(dao::isError()) return false;
  215. $expiredDomain = $this->setting->getItem('owner=system&module=common&section=domain&key=expiredDomain');
  216. $expiredDomain = empty($expiredDomain ) ? array(getenv('APP_DOMAIN')) : json_decode($expiredDomain, true);
  217. $expiredDomain[] = zget($settings, 'customDomain', '');
  218. $this->setting->setItem('system.common.domain.expiredDomain', json_encode($expiredDomain));
  219. $this->setting->setItem('system.common.domain.customDomain', zget($settings, 'customDomain', ''));
  220. $this->setting->setItem('system.common.domain.https', zget($settings, 'https', 'false'));
  221. $this->loadModel('instance')->updateInstancesDomain();
  222. $this->updateMinioDomain();
  223. }
  224. /**
  225. * 更新域名。
  226. * Update minio domain.
  227. *
  228. * @access public
  229. * @return void
  230. */
  231. public function updateMinioDomain()
  232. {
  233. $this->loadModel('cne');
  234. $sysDomain = $this->cne->sysDomain();
  235. $minioInstance = new stdclass;
  236. $minioInstance->k8name = 'cne-operator';
  237. $minioInstance->chart = 'cne-operator';
  238. $minioInstance->spaceData = new stdclass;
  239. $minioInstance->spaceData->k8space = $this->config->k8space;
  240. $settings = new stdclass;
  241. $settings->settings_map = new stdclass;
  242. $settings->settings_map->minio = new stdclass;
  243. $settings->settings_map->minio->ingress = new stdclass;
  244. $settings->settings_map->minio->ingress->enabled = true;
  245. $settings->settings_map->minio->ingress->host = 's3.' . $sysDomain;
  246. $this->cne->updateConfig($minioInstance, $settings);
  247. }
  248. /**
  249. * 创建备份。
  250. * Backup the instance.
  251. *
  252. * @param object $instance
  253. * @param string $mode |manual|system|upgrade|downgrade
  254. * @return array
  255. */
  256. public function backup($instance, $mode = '')
  257. {
  258. $this->loadModel('cne');
  259. if(empty($instance)) $instance = $this->config->instance->zentaopaas;
  260. if(empty($_SESSION['fromCron'])) $this->setMaintenance('backup');
  261. $rawResult = $this->cne->backup($instance, $this->app->user->account, $mode);
  262. if(!empty($rawResult->code) && $rawResult->code == 200)
  263. {
  264. return array('result' => 'success', 'message' => $rawResult->message, 'data' => $rawResult->data);
  265. }
  266. else
  267. {
  268. $this->unsetMaintenance('backup');
  269. return array('result' => 'fail', 'message' => $rawResult->message);
  270. }
  271. }
  272. /**
  273. * 获取备份状态。
  274. * Get backup status.
  275. *
  276. * @param object $instance
  277. * @param string $backup
  278. * @return array
  279. * @param string $backupName
  280. */
  281. public function getBackupStatus($instance, $backupName)
  282. {
  283. $this->loadModel('cne');
  284. $rawResult = $this->cne->getBackupStatus($instance, $backupName);
  285. if(!empty($rawResult->code) && $rawResult->code == 200)
  286. {
  287. return array('result' => 'success', 'message' => $rawResult->message, 'data' => $rawResult->data);
  288. }
  289. else
  290. {
  291. return array('result' => 'fail', 'message' => $rawResult->message);
  292. }
  293. }
  294. /**
  295. * 获取备份列表。
  296. * Get backup list.
  297. *
  298. * @param object $instance
  299. * @return array
  300. */
  301. public function getBackupList($instance)
  302. {
  303. $this->loadModel('cne');
  304. $rawResult = $this->cne->getBackupList($instance);
  305. if(!empty($rawResult->code) && $rawResult->code == 200)
  306. {
  307. return array('result' => 'success', 'message' => $rawResult->message, 'data' => $rawResult->data);
  308. }
  309. else
  310. {
  311. return array('result' => 'fail', 'message' => $rawResult->message);
  312. }
  313. }
  314. /**
  315. * 恢复一个备份。
  316. * Restore the backup.
  317. *
  318. * @param object $instance
  319. * @param string $backupName
  320. * @param string $account
  321. * @return array
  322. */
  323. public function restore($instance, $backupName, $account = '')
  324. {
  325. $this->loadModel('cne');
  326. $rawResult = $this->cne->restore($instance, $backupName, $account);
  327. if(!empty($rawResult->code) && $rawResult->code == 200)
  328. {
  329. return array('result' => 'success', 'message' => $rawResult->message, 'data' => $rawResult->data);
  330. }
  331. else
  332. {
  333. return array('result' => 'fail', 'message' => $rawResult->message);
  334. }
  335. }
  336. /**
  337. * 删除一个备份。
  338. * Delete the backup.
  339. *
  340. * @param object $instance
  341. * @param string $backupName
  342. * @return array
  343. */
  344. public function deleteBackup($instance, $backupName)
  345. {
  346. $this->loadModel('cne');
  347. $rawResult = $this->cne->deleteBackup($instance, $backupName);
  348. if(!empty($rawResult->code) && $rawResult->code == 200)
  349. {
  350. return array('result' => 'success', 'message' => $rawResult->message, 'data' => $rawResult->data);
  351. }
  352. else
  353. {
  354. return array('result' => 'fail', 'message' => $rawResult->message);
  355. }
  356. }
  357. /**
  358. * 设置系统维护信息。
  359. * Set maintenance message.
  360. *
  361. * @param string $action backup|restore|upgrade
  362. * @return bool
  363. */
  364. public function setMaintenance($action)
  365. {
  366. if(empty($action) || !in_array($action, array_keys($this->lang->system->maintenance->reason))) return false;
  367. $maintenance = new stdclass();
  368. $maintenance->action = $action;
  369. $maintenance->reason = zget($this->lang->system->maintenance->reason, $action, $this->lang->unknown);
  370. return $this->loadModel('setting')->setItem('system.system.maintenance', json_encode($maintenance));
  371. }
  372. /**
  373. * 复原系统维护信息。
  374. * Unset Maintenance message.
  375. *
  376. * @return void
  377. */
  378. public function unsetMaintenance()
  379. {
  380. $maintenance = $this->loadModel('setting')->getItem('owner=system&module=system&key=maintenance');
  381. if(empty($maintenance)) return;
  382. $this->setting->deleteItems('owner=system&module=system&key=maintenance');
  383. }
  384. /**
  385. * 从云API服务器获取最新的发布版本。
  386. * Get the latest release from cloud API server.
  387. *
  388. * @return object
  389. */
  390. public function getLatestRelease()
  391. {
  392. $cloudApiHost = getenv('CLOUD_API_HOST');
  393. if(empty($cloudApiHost)) $cloudApiHost = $this->config->cloud->api->host;
  394. $currentRelease = array(
  395. 'name' => 'zentaopaas',
  396. 'channel' => getenv('CLOUD_DEFAULT_CHANNEL') ?: 'stable',
  397. 'version' => getenv('APP_VERSION')
  398. );
  399. $ztVersion = $this->loadModel('upgrade')->getOpenVersion(str_replace('.', '_', $this->config->version));
  400. $currentRelease['zentao_version'] = str_replace('_', '.', $ztVersion);
  401. $query = http_build_query($currentRelease);
  402. $response = common::http($cloudApiHost . '/api/market/app/version/latest?' . $query);
  403. if($response)
  404. {
  405. $response =json_decode($response);
  406. if($response && $response->code == 200) return $response->data;
  407. }
  408. return false;
  409. }
  410. /**
  411. * 检查当前版本是否可升级。
  412. * Check if the current release is upgradeable.
  413. *
  414. * @return bool
  415. */
  416. public function isUpgradeable()
  417. {
  418. $latestRelease = $this->getLatestRelease();
  419. if(!$latestRelease) return false;
  420. $latestVersion = false;
  421. if(isset($latestRelease->products->{$this->config->edition}))
  422. $latestVersion = $latestRelease->products->{$this->config->edition};
  423. else
  424. $latestVersion = $latestRelease->products->oss;
  425. if(version_compare($latestVersion, $this->config->version, 'lt')) return false;
  426. $chartVersion = getenv('CHART_VERSION');
  427. if(empty($chartVersion)) return false;
  428. if(version_compare($latestRelease->version, $chartVersion, 'gt')) return true;
  429. return false;
  430. }
  431. /**
  432. * 检查按钮是否可用。
  433. * Check if the button is clickable.
  434. *
  435. * @param object $system
  436. * @param string $action
  437. * @access public
  438. * @return bool
  439. */
  440. public function isClickable($system, $action)
  441. {
  442. if($action == 'active') return $system->status == 'inactive';
  443. if($action == 'inactive') return $system->status == 'active';
  444. return true;
  445. }
  446. /**
  447. * 更新应用的最新发布信息。
  448. * Update the latest release of the app.
  449. *
  450. * @param int $systemID
  451. * @param int $releaseID
  452. * @param string $releasedDate
  453. * @access public
  454. * @return bool
  455. */
  456. public function setSystemRelease($systemID, $releaseID, $releasedDate = '')
  457. {
  458. $system = $this->fetchByID($systemID);
  459. if(!$system) return false;
  460. if(empty($releasedDate))
  461. {
  462. if($releaseID != $system->latestRelease) return false;
  463. $release = $this->dao->select('id,createdDate')->from(TABLE_RELEASE)->where('deleted')->eq(0)->andWhere('system')->eq($systemID)->orderBy('id DESC')->fetch();
  464. $releaseID = $release ? $release->id : 0;
  465. $releasedDate = $release ? $release->createdDate : null;
  466. }
  467. $this->dao->update(TABLE_SYSTEM)->set('latestDate')->eq($releasedDate)->set('latestRelease')->eq($releaseID)->where('id')->eq($systemID)->exec();
  468. return !dao::isError();
  469. }
  470. /**
  471. * 根据ID获取发布信息。
  472. * Get release information by ID.
  473. *
  474. * @param int $systemID
  475. * @access public
  476. * @return array
  477. */
  478. public function getReleasesByID($systemID)
  479. {
  480. return $this->dao->select('*')->from(TABLE_RELEASE)
  481. ->where('system')->eq($systemID)
  482. ->andWhere('deleted')->eq(0)
  483. ->fetchAll('id');
  484. }
  485. /**
  486. * 根据ID获取构建信息。
  487. * Get build information by ID.
  488. *
  489. * @param int $systemID
  490. * @access public
  491. * @return array
  492. */
  493. public function getBuildsByID($systemID)
  494. {
  495. return $this->dao->select('*')->from(TABLE_BUILD)
  496. ->where('system')->eq($systemID)
  497. ->andWhere('deleted')->eq(0)
  498. ->fetchAll('id');
  499. }
  500. /**
  501. * 初始化应用。
  502. * Initialize application.
  503. *
  504. * @access public
  505. * @return bool
  506. */
  507. public function initSystem()
  508. {
  509. $productPairs = $this->dao->select('*')->from(TABLE_PRODUCT)->where('deleted')->eq('0')->fetchPairs('id', 'name');
  510. $releasePairs = $this->dao->select('id,product,date,createdDate')->from(TABLE_RELEASE)->where('deleted')->eq('0')->fetchAll('product');
  511. $systemPairs = array();
  512. $systemNames = array();
  513. $systemList = $this->dao->select('id,product,name')->from(TABLE_SYSTEM)->where('deleted')->eq('0')->fetchAll();
  514. foreach($systemList as $system)
  515. {
  516. $system->name = strtolower($system->name);
  517. $systemNames[$system->name] = $system->id;
  518. $systemPairs[$system->product] = $system->id;
  519. }
  520. $system = new stdclass();
  521. $system->createdDate = helper::now();
  522. $system->createdBy = 'system';
  523. foreach($productPairs as $productID => $productName)
  524. {
  525. $systemID = zget($systemPairs, $productID, 0);
  526. if(!$systemID)
  527. {
  528. if(isset($systemNames[strtolower($productName)])) $productName .= '-1';
  529. $system->name = $productName;
  530. $system->product = $productID;
  531. $system->latestDate = null;
  532. $system->latestRelease = 0;
  533. if(isset($releasePairs[$productID]))
  534. {
  535. $system->latestDate = $releasePairs[$productID]->createdDate ? $releasePairs[$productID]->createdDate : "{$releasePairs[$productID]->date} 00:00:00";
  536. $system->latestRelease = $releasePairs[$productID]->id;
  537. }
  538. $systemID = $this->create($system);
  539. if(dao::isError()) continue;
  540. }
  541. $this->dao->update(TABLE_BUILD)->set('system')->eq($systemID)->where('product')->eq($productID)->andWhere('system')->eq(0)->exec();
  542. $this->dao->update(TABLE_RELEASE)->set('system')->eq($systemID)->where('product')->eq($productID)->andWhere('system')->eq(0)->exec();
  543. }
  544. if(!dao::isError()) $this->dao->delete()->from(TABLE_CRON)->where('command')->eq('moduleName=system&methodName=initSystem')->exec();
  545. return dao::isError();
  546. }
  547. }