248 lines
7.5 KiB
PHP
248 lines
7.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\admin\controller;
|
|
|
|
use app\admin\model\Domain as DomainModel;
|
|
use app\common\controller\Backend;
|
|
use app\common\service\CloudflareService;
|
|
use app\common\service\DomainDetectRateLimitService;
|
|
use think\Db;
|
|
use think\Exception;
|
|
use think\exception\PDOException;
|
|
use think\exception\ValidateException;
|
|
|
|
/**
|
|
* 域名管理
|
|
*
|
|
* @icon fa fa-globe
|
|
* @remark 域名接入Cloudflare,新增后请在详情查看NS并到注册商修改
|
|
*/
|
|
class Domain extends Backend
|
|
{
|
|
/** @var DomainModel */
|
|
protected $model = null;
|
|
|
|
protected $searchFields = 'domain';
|
|
protected $dataLimit = 'personal';
|
|
protected $modelValidate = true;
|
|
protected $modelSceneValidate = true;
|
|
|
|
public function _initialize()
|
|
{
|
|
parent::_initialize();
|
|
$this->model = new DomainModel();
|
|
$this->view->assign('zoneStatusList', $this->model->getZoneStatusList());
|
|
$this->view->assign('nsStatusList', $this->model->getNsStatusList());
|
|
$this->view->assign('dnsStatusList', $this->model->getDnsStatusList());
|
|
$this->assignconfig('zoneStatusList', $this->model->getZoneStatusList());
|
|
$this->assignconfig('nsStatusList', $this->model->getNsStatusList());
|
|
$this->assignconfig('dnsStatusList', $this->model->getDnsStatusList());
|
|
}
|
|
|
|
/**
|
|
* 禁止编辑
|
|
*/
|
|
public function edit($ids = null)
|
|
{
|
|
$this->error(__('Domain cannot be edited after creation'));
|
|
}
|
|
|
|
/**
|
|
* 禁止批量操作
|
|
*/
|
|
public function multi($ids = '')
|
|
{
|
|
$this->error(__('Invalid parameters'));
|
|
}
|
|
|
|
/**
|
|
* 添加域名并创建 Cloudflare Zone
|
|
*/
|
|
public function add()
|
|
{
|
|
if (false === $this->request->isPost()) {
|
|
return $this->view->fetch();
|
|
}
|
|
|
|
$params = $this->request->post('row/a', []);
|
|
if ($params === []) {
|
|
$this->error(__('Parameter %s can not be empty', ''));
|
|
}
|
|
|
|
$params = $this->preExcludeFields($params);
|
|
$domain = DomainModel::normalizeDomain((string)($params['domain'] ?? ''));
|
|
$params['domain'] = $domain;
|
|
|
|
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
|
|
$params[$this->dataLimitField] = $this->auth->id;
|
|
}
|
|
|
|
$result = false;
|
|
Db::startTrans();
|
|
try {
|
|
if ($this->modelValidate) {
|
|
$name = str_replace('\\model\\', '\\validate\\', get_class($this->model));
|
|
$validate = $this->modelSceneValidate ? $name . '.add' : $name;
|
|
$this->model->validateFailException()->validate($validate, $params);
|
|
}
|
|
|
|
if (DomainModel::where('domain', $domain)->find()) {
|
|
throw new ValidateException(__('Domain already exists'));
|
|
}
|
|
|
|
$cloudflare = new CloudflareService();
|
|
$zone = $cloudflare->createZone($domain);
|
|
|
|
$params['full_url'] = 'https://' . $domain;
|
|
$params['zone_id'] = $zone['zone_id'];
|
|
$params['nameservers'] = $zone['name_servers'];
|
|
$params['zone_status'] = DomainModel::mapCloudflareZoneStatus($zone['status']);
|
|
$params['ns_status'] = 'pending';
|
|
$params['dns_status'] = 'pending';
|
|
$params['check_result'] = '';
|
|
|
|
$result = $this->model->allowField(true)->save($params);
|
|
Db::commit();
|
|
} catch (ValidateException $e) {
|
|
Db::rollback();
|
|
$this->error($e->getMessage());
|
|
} catch (PDOException|Exception $e) {
|
|
Db::rollback();
|
|
$this->error($e->getMessage());
|
|
}
|
|
|
|
if ($result === false) {
|
|
$this->error(__('No rows were inserted'));
|
|
}
|
|
|
|
$this->success(__('Domain submitted, please check NS in detail page and update at registrar'));
|
|
}
|
|
|
|
/**
|
|
* 域名详情
|
|
*/
|
|
public function detail($ids = null)
|
|
{
|
|
$row = $this->model->get($ids);
|
|
if (!$row) {
|
|
$this->error(__('No Results were found'));
|
|
}
|
|
if (!$this->checkDataLimit($row)) {
|
|
$this->error(__('You have no permission'));
|
|
}
|
|
|
|
$data = $row->toArray();
|
|
$data['nameservers_list'] = $row->getNameserversArray();
|
|
$this->view->assign('row', $data);
|
|
return $this->view->fetch();
|
|
}
|
|
|
|
/**
|
|
* 检测域名状态
|
|
*/
|
|
public function detect($ids = null)
|
|
{
|
|
if (!$this->request->isPost()) {
|
|
$this->error(__('Invalid parameters'));
|
|
}
|
|
|
|
$row = $this->model->get($ids);
|
|
if (!$row) {
|
|
$this->error(__('No Results were found'));
|
|
}
|
|
if (!$this->checkDataLimit($row)) {
|
|
$this->error(__('You have no permission'));
|
|
}
|
|
|
|
try {
|
|
(new DomainDetectRateLimitService())->assertCanDetect((int)$this->auth->id, (int)$row['id']);
|
|
} catch (Exception $e) {
|
|
$this->error($e->getMessage());
|
|
}
|
|
|
|
try {
|
|
$cloudflare = new CloudflareService();
|
|
$detect = $cloudflare->detectDomain($row->toArray());
|
|
$row->save([
|
|
'zone_status' => $detect['zone_status'],
|
|
'ns_status' => $detect['ns_status'],
|
|
'dns_status' => $detect['dns_status'],
|
|
'check_time' => time(),
|
|
'check_result' => $detect['check_result'],
|
|
]);
|
|
} catch (Exception $e) {
|
|
$this->error($e->getMessage());
|
|
}
|
|
|
|
$this->success(__('Detection completed'), null, $row->toArray());
|
|
}
|
|
|
|
/**
|
|
* 删除(需输入完整域名二次确认)
|
|
*/
|
|
public function del($ids = '')
|
|
{
|
|
if (!$this->request->isPost()) {
|
|
$this->error(__('Invalid parameters'));
|
|
}
|
|
|
|
$ids = $ids ?: $this->request->post('ids', '');
|
|
$confirmDomain = trim((string)$this->request->post('confirm_domain', ''));
|
|
if ($ids === '' || $confirmDomain === '') {
|
|
$this->error(__('Please enter the full domain to confirm deletion'));
|
|
}
|
|
|
|
$pk = $this->model->getPk();
|
|
$list = $this->model->where($pk, 'in', $ids)->select();
|
|
if (!$list || count($list) === 0) {
|
|
$this->error(__('No Results were found'));
|
|
}
|
|
|
|
$count = 0;
|
|
Db::startTrans();
|
|
try {
|
|
foreach ($list as $item) {
|
|
if (!$this->checkDataLimit($item)) {
|
|
throw new Exception(__('You have no permission'));
|
|
}
|
|
if (DomainModel::normalizeDomain($confirmDomain) !== DomainModel::normalizeDomain((string)$item['domain'])) {
|
|
throw new Exception(__('Domain confirmation does not match'));
|
|
}
|
|
|
|
if (!empty($item['zone_id'])) {
|
|
$cloudflare = new CloudflareService();
|
|
$cloudflare->deleteZone((string)$item['zone_id']);
|
|
}
|
|
|
|
$count += $item->delete();
|
|
}
|
|
Db::commit();
|
|
} catch (PDOException|Exception $e) {
|
|
Db::rollback();
|
|
$this->error($e->getMessage());
|
|
}
|
|
|
|
if ($count > 0) {
|
|
$this->success();
|
|
}
|
|
$this->error(__('No rows were deleted'));
|
|
}
|
|
|
|
/**
|
|
* @param DomainModel $row
|
|
*/
|
|
protected function checkDataLimit($row): bool
|
|
{
|
|
if (!$this->dataLimit) {
|
|
return true;
|
|
}
|
|
$adminIds = $this->getDataLimitAdminIds();
|
|
if (!is_array($adminIds)) {
|
|
return true;
|
|
}
|
|
return in_array((int)$row[$this->dataLimitField], $adminIds, true);
|
|
}
|
|
}
|