mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-14 01:34:47 +08:00
feat: 优化网站域名添加 (#6069)
This commit is contained in:
parent
94b5a7fae4
commit
a225d2d79a
@ -13,15 +13,15 @@ type WebsiteSearch struct {
|
||||
}
|
||||
|
||||
type WebsiteCreate struct {
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
Alias string `json:"alias" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
OtherDomains string `json:"otherDomains"`
|
||||
Proxy string `json:"proxy"`
|
||||
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
|
||||
IPV6 bool `json:"IPV6"`
|
||||
|
||||
Domains []WebsiteDomain `json:"domains"`
|
||||
|
||||
AppType string `json:"appType" validate:"oneof=new installed"`
|
||||
AppInstall NewAppInstall `json:"appInstall"`
|
||||
AppID uint `json:"appID"`
|
||||
@ -124,7 +124,13 @@ type WebsiteGroupUpdate struct {
|
||||
|
||||
type WebsiteDomainCreate struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
Domains string `json:"domains" validate:"required"`
|
||||
Domains []WebsiteDomain `json:"domains" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteDomain struct {
|
||||
Domain string `json:"domain" validate:"required"`
|
||||
Port int `json:"port"`
|
||||
SSL bool `json:"SSL"`
|
||||
}
|
||||
|
||||
type WebsiteDomainDelete struct {
|
||||
@ -145,7 +151,7 @@ type WebsiteHTTPSOp struct {
|
||||
SSLProtocol []string `json:"SSLProtocol"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Hsts bool `json:"hsts"`
|
||||
HttpsPort int `json:"httpsPort"`
|
||||
HttpsPorts []int `json:"httpsPorts"`
|
||||
}
|
||||
|
||||
type WebsiteNginxUpdate struct {
|
||||
|
@ -59,7 +59,8 @@ type WebsiteHTTPS struct {
|
||||
SSLProtocol []string `json:"SSLProtocol"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Hsts bool `json:"hsts"`
|
||||
HttpsPort int `json:"httpsPort"`
|
||||
HttpsPorts []int `json:"httpsPorts"`
|
||||
HttpsPort string `json:"httpsPort"`
|
||||
}
|
||||
|
||||
type WebsiteLog struct {
|
||||
|
@ -28,8 +28,6 @@ type Website struct {
|
||||
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
||||
FtpID uint `gorm:"type:integer" json:"ftpId"`
|
||||
|
||||
HttpsPort int `json:"httpsPort"`
|
||||
|
||||
User string `gorm:"type:varchar;" json:"user"`
|
||||
Group string `gorm:"type:varchar;" json:"group"`
|
||||
|
||||
|
@ -4,6 +4,7 @@ type WebsiteDomain struct {
|
||||
BaseModel
|
||||
WebsiteID uint `gorm:"column:website_id;type:varchar(64);not null;" json:"websiteId"`
|
||||
Domain string `gorm:"type:varchar(256);not null" json:"domain"`
|
||||
SSL bool `json:"SSL"`
|
||||
Port int `gorm:"type:integer" json:"port"`
|
||||
}
|
||||
|
||||
|
@ -225,28 +225,21 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
return err
|
||||
}
|
||||
defaultHttpPort := nginxInstall.HttpPort
|
||||
defaultHttpsPort := nginxInstall.HttpsPort
|
||||
|
||||
var (
|
||||
otherDomains []model.WebsiteDomain
|
||||
domains []model.WebsiteDomain
|
||||
)
|
||||
domains, _, _, err = getWebsiteDomains(create.PrimaryDomain, defaultHttpPort, 0)
|
||||
domains, _, _, err = getWebsiteDomains(create.Domains, defaultHttpPort, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
otherDomains, _, _, err = getWebsiteDomains(create.OtherDomains, defaultHttpPort, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domains = append(domains, otherDomains...)
|
||||
if len(domains) == 1 && domains[0].Port != defaultHttpPort {
|
||||
defaultHttpsPort = domains[0].Port
|
||||
primaryDomain := domains[0].Domain
|
||||
if domains[0].Port != defaultHttpPort {
|
||||
primaryDomain = fmt.Sprintf("%s:%v", domains[0].Domain, domains[0].Port)
|
||||
}
|
||||
|
||||
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
||||
website := &model.Website{
|
||||
PrimaryDomain: create.PrimaryDomain,
|
||||
PrimaryDomain: primaryDomain,
|
||||
Type: create.Type,
|
||||
Alias: alias,
|
||||
Remark: create.Remark,
|
||||
@ -259,7 +252,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
AccessLog: true,
|
||||
ErrorLog: true,
|
||||
IPV6: create.IPV6,
|
||||
HttpsPort: defaultHttpsPort,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -267,7 +259,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
runtime *model.Runtime
|
||||
)
|
||||
|
||||
createTask, err := task.NewTaskWithOps(create.PrimaryDomain, task.TaskCreate, task.TaskScopeWebsite, create.TaskID, 0)
|
||||
createTask, err := task.NewTaskWithOps(primaryDomain, task.TaskCreate, task.TaskScopeWebsite, create.TaskID, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -464,7 +456,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
SSLProtocol: []string{"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"},
|
||||
Algorithm: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED",
|
||||
Hsts: true,
|
||||
HttpsPort: website.HttpsPort,
|
||||
}
|
||||
if err = applySSL(website, *websiteModel, appSSLReq); err != nil {
|
||||
return err
|
||||
@ -607,7 +598,6 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
var (
|
||||
domainModels []model.WebsiteDomain
|
||||
addPorts []int
|
||||
addDomains []string
|
||||
)
|
||||
httpPort, _, err := getAppInstallPort(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
@ -618,7 +608,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domainModels, addPorts, addDomains, err = getWebsiteDomains(create.Domains, httpPort, create.WebsiteID)
|
||||
domainModels, addPorts, _, err = getWebsiteDomains(create.Domains, httpPort, create.WebsiteID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -626,7 +616,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
_ = OperateFirewallPort(nil, addPorts)
|
||||
}()
|
||||
|
||||
if err := addListenAndServerName(website, addPorts, addDomains); err != nil {
|
||||
if err = addListenAndServerName(website, domainModels); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -868,8 +858,22 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
|
||||
if err != nil {
|
||||
return response.WebsiteHTTPS{}, err
|
||||
}
|
||||
var res response.WebsiteHTTPS
|
||||
res.HttpsPort = website.HttpsPort
|
||||
var (
|
||||
res response.WebsiteHTTPS
|
||||
httpsPorts []string
|
||||
)
|
||||
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteId))
|
||||
for _, domain := range websiteDomains {
|
||||
if domain.SSL {
|
||||
httpsPorts = append(httpsPorts, strconv.Itoa(domain.Port))
|
||||
}
|
||||
}
|
||||
if len(httpsPorts) == 0 {
|
||||
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||
res.HttpsPort = strconv.Itoa(nginxInstall.HttpsPort)
|
||||
} else {
|
||||
res.HttpsPort = strings.Join(httpsPorts, ",")
|
||||
}
|
||||
if website.WebsiteSSLID == 0 {
|
||||
res.Enable = false
|
||||
return res, nil
|
||||
@ -925,17 +929,17 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
if !req.Enable {
|
||||
website.Protocol = constant.ProtocolHTTP
|
||||
website.WebsiteSSLID = 0
|
||||
httpsPort := website.HttpsPort
|
||||
if httpsPort == 0 {
|
||||
_, httpsPort, err = getAppInstallPort(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
httpsPortStr := strconv.Itoa(httpsPort)
|
||||
if err := deleteListenAndServerName(website, []string{httpsPortStr, "[::]:" + httpsPortStr}, []string{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//httpsPort := req.HttpsPort
|
||||
//if len(httpsPort) == 0 {
|
||||
// _, httpsPort, err = getAppInstallPort(constant.AppOpenresty)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//}
|
||||
//httpsPortStr := strconv.Itoa(httpsPort)
|
||||
//if err = deleteListenAndServerName(website, []string{httpsPortStr, "[::]:" + httpsPortStr}, []string{}); err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
nginxParams := getNginxParamsFromStaticFile(dto.SSL, nil)
|
||||
nginxParams = append(nginxParams,
|
||||
dto.NginxParam{
|
||||
@ -1035,18 +1039,18 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
}
|
||||
|
||||
website.Protocol = constant.ProtocolHTTPS
|
||||
if err := applySSL(&website, websiteSSL, req); err != nil {
|
||||
if err = applySSL(&website, websiteSSL, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
website.HttpConfig = req.HttpConfig
|
||||
|
||||
if websiteSSL.ID == 0 {
|
||||
if err := websiteSSLRepo.Create(ctx, &websiteSSL); err != nil {
|
||||
if err = websiteSSLRepo.Create(ctx, &websiteSSL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
website.WebsiteSSLID = websiteSSL.ID
|
||||
}
|
||||
if err := websiteRepo.Save(ctx, &website); err != nil {
|
||||
if err = websiteRepo.Save(ctx, &website); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -35,40 +34,6 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func getDomain(domainStr string, defaultPort int) (model.WebsiteDomain, error) {
|
||||
var (
|
||||
err error
|
||||
domain = model.WebsiteDomain{}
|
||||
portN int
|
||||
)
|
||||
domainArray := strings.Split(domainStr, ":")
|
||||
if len(domainArray) == 1 {
|
||||
domain.Domain, err = handleChineseDomain(domainArray[0])
|
||||
if err != nil {
|
||||
return domain, err
|
||||
}
|
||||
domain.Port = defaultPort
|
||||
return domain, nil
|
||||
}
|
||||
if len(domainArray) > 1 {
|
||||
domain.Domain, err = handleChineseDomain(domainArray[0])
|
||||
if err != nil {
|
||||
return domain, err
|
||||
}
|
||||
portStr := domainArray[1]
|
||||
portN, err = strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return domain, buserr.WithName("ErrTypePort", portStr)
|
||||
}
|
||||
if portN <= 0 || portN > 65535 {
|
||||
return domain, buserr.New("ErrTypePortRange")
|
||||
}
|
||||
domain.Port = portN
|
||||
return domain, nil
|
||||
}
|
||||
return domain, nil
|
||||
}
|
||||
|
||||
func handleChineseDomain(domain string) (string, error) {
|
||||
if common.ContainsChinese(domain) {
|
||||
return common.PunycodeEncode(domain)
|
||||
@ -481,7 +446,7 @@ func delWafConfig(website model.Website, force bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func addListenAndServerName(website model.Website, ports []int, domains []string) error {
|
||||
func addListenAndServerName(website model.Website, domains []model.WebsiteDomain) error {
|
||||
nginxFull, err := getNginxFull(&website)
|
||||
if err != nil {
|
||||
return nil
|
||||
@ -489,16 +454,20 @@ func addListenAndServerName(website model.Website, ports []int, domains []string
|
||||
nginxConfig := nginxFull.SiteConfig
|
||||
config := nginxFull.SiteConfig.Config
|
||||
server := config.FindServers()[0]
|
||||
for _, port := range ports {
|
||||
server.AddListen(strconv.Itoa(port), false)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:"+strconv.Itoa(port), false)
|
||||
}
|
||||
}
|
||||
|
||||
for _, domain := range domains {
|
||||
server.AddServerName(domain)
|
||||
var params []string
|
||||
if website.Protocol == constant.ProtocolHTTPS && domain.SSL {
|
||||
params = append(params, "ssl", "http2")
|
||||
}
|
||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
server.AddListen(strconv.Itoa(domain.Port), false, params...)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:"+strconv.Itoa(domain.Port), false, params...)
|
||||
}
|
||||
server.UpdateServerName([]string{domain.Domain})
|
||||
}
|
||||
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
return nginxCheckAndReload(nginxConfig.OldContent, nginxConfig.FilePath, nginxFull.Install.ContainerName)
|
||||
@ -568,6 +537,24 @@ func createPemFile(website model.Website, websiteSSL model.WebsiteSSL) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHttpsPort(website *model.Website) ([]int, error) {
|
||||
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(website.ID))
|
||||
var httpsPorts []int
|
||||
for _, domain := range websiteDomains {
|
||||
if domain.SSL {
|
||||
httpsPorts = append(httpsPorts, domain.Port)
|
||||
}
|
||||
}
|
||||
if len(httpsPorts) == 0 {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpsPorts = append(httpsPorts, nginxInstall.HttpsPort)
|
||||
}
|
||||
return httpsPorts, nil
|
||||
}
|
||||
|
||||
func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.WebsiteHTTPSOp) error {
|
||||
nginxFull, err := getNginxFull(website)
|
||||
if err != nil {
|
||||
@ -587,18 +574,19 @@ func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.W
|
||||
server := config.FindServers()[0]
|
||||
|
||||
httpPort := strconv.Itoa(nginxFull.Install.HttpPort)
|
||||
httpsPort := nginxFull.Install.HttpsPort
|
||||
if req.HttpsPort > 0 {
|
||||
httpsPort = req.HttpsPort
|
||||
httpsPort, err := getHttpsPort(website)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
website.HttpsPort = httpsPort
|
||||
httpPortIPV6 := "[::]:" + httpPort
|
||||
httpsPortIPV6 := "[::]:" + strconv.Itoa(httpsPort)
|
||||
|
||||
server.UpdateListen(strconv.Itoa(httpsPort), website.DefaultServer, "ssl", "http2")
|
||||
for _, port := range httpsPort {
|
||||
httpsPortIPV6 := "[::]:" + strconv.Itoa(port)
|
||||
server.UpdateListen(strconv.Itoa(port), website.DefaultServer, "ssl", "http2")
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(httpsPortIPV6, website.DefaultServer, "ssl", "http2")
|
||||
}
|
||||
}
|
||||
|
||||
switch req.HttpConfig {
|
||||
case constant.HTTPSOnly:
|
||||
@ -911,30 +899,36 @@ func changeServiceName(newComposeContent, newServiceName string) (composeByte []
|
||||
return yaml.Marshal(composeMap)
|
||||
}
|
||||
|
||||
func getWebsiteDomains(domains string, defaultPort int, websiteID uint) (domainModels []model.WebsiteDomain, addPorts []int, addDomains []string, err error) {
|
||||
func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, websiteID uint) (domainModels []model.WebsiteDomain, addPorts []int, addDomains []string, err error) {
|
||||
var (
|
||||
ports = make(map[int]struct{})
|
||||
existPort = make(map[int]struct{})
|
||||
)
|
||||
domainArray := strings.Split(domains, "\n")
|
||||
for _, domain := range domainArray {
|
||||
if domain == "" {
|
||||
existDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteID))
|
||||
for _, domain := range existDomains {
|
||||
existPort[domain.Port] = struct{}{}
|
||||
}
|
||||
for _, domain := range domains {
|
||||
if domain.Domain == "" {
|
||||
continue
|
||||
}
|
||||
if !common.IsValidDomain(domain) {
|
||||
err = buserr.WithName("ErrDomainFormat", domain)
|
||||
if !common.IsValidDomain(domain.Domain) {
|
||||
err = buserr.WithName("ErrDomainFormat", domain.Domain)
|
||||
return
|
||||
}
|
||||
var domainModel model.WebsiteDomain
|
||||
domainModel, err = getDomain(domain, defaultPort)
|
||||
domainModel.Domain, err = handleChineseDomain(domain.Domain)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if reflect.DeepEqual(domainModel, model.WebsiteDomain{}) {
|
||||
continue
|
||||
domainModel.Port = domain.Port
|
||||
if domain.Port == 0 {
|
||||
domain.Port = defaultPort
|
||||
}
|
||||
domainModel.SSL = domain.SSL
|
||||
domainModel.WebsiteID = websiteID
|
||||
domainModels = append(domainModels, domainModel)
|
||||
if domainModel.Port != defaultPort {
|
||||
if _, ok := existPort[domainModel.Port]; !ok {
|
||||
ports[domainModel.Port] = struct{}{}
|
||||
}
|
||||
if exist, _ := websiteDomainRepo.GetFirst(websiteDomainRepo.WithDomain(domainModel.Domain), websiteDomainRepo.WithWebsiteId(websiteID)); exist.ID == 0 {
|
||||
@ -950,6 +944,10 @@ func getWebsiteDomains(domains string, defaultPort int, websiteID uint) (domainM
|
||||
}
|
||||
|
||||
for port := range ports {
|
||||
if port == defaultPort {
|
||||
addPorts = append(addPorts, port)
|
||||
continue
|
||||
}
|
||||
if existPorts, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithPort(port)); len(existPorts) == 0 {
|
||||
errMap := make(map[string]interface{})
|
||||
errMap["port"] = port
|
||||
|
@ -19,6 +19,7 @@ func Init() {
|
||||
migrations.InitPHPExtensions,
|
||||
migrations.AddTask,
|
||||
migrations.UpdateWebsite,
|
||||
migrations.UpdateWebsiteDomain,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
@ -296,3 +296,11 @@ var UpdateWebsite = &gormigrate.Migration{
|
||||
&model.Website{})
|
||||
},
|
||||
}
|
||||
|
||||
var UpdateWebsiteDomain = &gormigrate.Migration{
|
||||
ID: "20240808-update-website-domain",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(
|
||||
&model.WebsiteDomain{})
|
||||
},
|
||||
}
|
||||
|
@ -67,14 +67,12 @@ export namespace Website {
|
||||
}
|
||||
|
||||
export interface WebSiteCreateReq {
|
||||
primaryDomain: string;
|
||||
type: string;
|
||||
alias: string;
|
||||
remark: string;
|
||||
appType: string;
|
||||
appInstallId: number;
|
||||
webSiteGroupId: number;
|
||||
otherDomains: string;
|
||||
proxy: string;
|
||||
proxyType: string;
|
||||
ftpUser: string;
|
||||
@ -88,6 +86,7 @@ export namespace Website {
|
||||
dbFormat?: string;
|
||||
dbUser?: string;
|
||||
dbHost?: string;
|
||||
domains: SubDomain[];
|
||||
}
|
||||
|
||||
export interface WebSiteUpdateReq {
|
||||
@ -128,7 +127,13 @@ export namespace Website {
|
||||
|
||||
export interface DomainCreate {
|
||||
websiteID: number;
|
||||
domains: string;
|
||||
domains: SubDomain[];
|
||||
}
|
||||
|
||||
interface SubDomain {
|
||||
domain: string;
|
||||
port: number;
|
||||
ssl: boolean;
|
||||
}
|
||||
|
||||
export interface DomainDelete {
|
||||
@ -288,7 +293,7 @@ export namespace Website {
|
||||
SSLProtocol: string[];
|
||||
algorithm: string;
|
||||
hsts: boolean;
|
||||
httpsPort: number;
|
||||
httpsPort?: string;
|
||||
}
|
||||
|
||||
export interface CheckReq {
|
||||
|
@ -2130,6 +2130,8 @@ const message = {
|
||||
"When the reverse proxy backend is HTTPS, you might need to set the origin SNI. Please refer to the CDN service provider's documentation for details.",
|
||||
createDb: 'Create Database',
|
||||
enableSSLHelper: 'Failure to enable will not affect the creation of the website',
|
||||
batchAdd: 'Batch Add Domains',
|
||||
generateDomain: 'Generate',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: 'Short tag support',
|
||||
|
@ -1980,6 +1980,8 @@ const message = {
|
||||
sniHelper: '反代後端為 https 的時候可能需要設置回源 SNI,具體需要看 CDN 服務商文檔',
|
||||
createDb: '建立資料庫',
|
||||
enableSSLHelper: '開啟失敗不會影響網站創建',
|
||||
batchAdd: '批量添加域名',
|
||||
generateDomain: '生成',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短標簽支持',
|
||||
|
@ -1982,6 +1982,8 @@ const message = {
|
||||
sniHelper: '反代后端为 https 的时候可能需要设置回源 SNI,具体需要看 CDN 服务商文档',
|
||||
createDb: '创建数据库',
|
||||
enableSSLHelper: '开启失败不会影响网站创建',
|
||||
batchAdd: '批量添加域名',
|
||||
generateDomain: '生成',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短标签支持',
|
||||
|
@ -1,30 +1,8 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="open"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:title="$t('website.addDomain')"
|
||||
size="40%"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('website.addDomain')" :back="handleClose" />
|
||||
</template>
|
||||
|
||||
<el-row v-loading="loading">
|
||||
<el-col :span="22" :offset="1">
|
||||
<el-form ref="domainForm" label-position="top" :model="domain" :rules="rules">
|
||||
<el-form-item :label="$t('website.domain')" prop="domains">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
v-model="domain.domains"
|
||||
:placeholder="$t('website.domainHelper')"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<DrawerPro v-model="open" :header="$t('website.addDomain')" :back="handleClose">
|
||||
<el-form ref="domainForm" label-position="top" :model="create">
|
||||
<DomainCreate v-model:form="create"></DomainCreate>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
@ -33,29 +11,31 @@
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</DrawerPro>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { CreateDomain } from '@/api/modules/website';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import DomainCreate from '@/views/website/website/domain-create/index.vue';
|
||||
|
||||
const domainForm = ref<FormInstance>();
|
||||
|
||||
const rules = ref({
|
||||
domains: [Rules.requiredInput],
|
||||
const initDomain = () => ({
|
||||
domain: '',
|
||||
port: 80,
|
||||
ssl: false,
|
||||
});
|
||||
|
||||
const open = ref(false);
|
||||
const loading = ref(false);
|
||||
const domain = ref({
|
||||
const create = ref({
|
||||
websiteID: 0,
|
||||
domains: '',
|
||||
domains: [initDomain()],
|
||||
domainStr: '',
|
||||
});
|
||||
|
||||
const em = defineEmits(['close']);
|
||||
@ -66,7 +46,9 @@ const handleClose = () => {
|
||||
};
|
||||
|
||||
const acceptParams = async (websiteId: number) => {
|
||||
domain.value.websiteID = Number(websiteId);
|
||||
create.value.websiteID = Number(websiteId);
|
||||
create.value.domains = [initDomain()];
|
||||
create.value.domainStr = '';
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
@ -77,7 +59,7 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
CreateDomain(domain.value)
|
||||
CreateDomain(create.value)
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
|
||||
handleClose();
|
||||
|
@ -13,8 +13,8 @@
|
||||
<el-switch v-model="form.enable" @change="changeEnable"></el-switch>
|
||||
</el-form-item>
|
||||
<div v-if="form.enable">
|
||||
<el-form-item :label="'HTTPS ' + $t('commons.table.port')" prop="httpsPort">
|
||||
<el-input v-model.number="form.httpsPort" />
|
||||
<el-form-item :label="'HTTPS ' + $t('commons.table.port')" prop="HttpsPort">
|
||||
<el-text>{{ form.httpsPort }}</el-text>
|
||||
</el-form-item>
|
||||
<el-text type="warning" class="!ml-2">{{ $t('website.ipWebsiteWarn') }}</el-text>
|
||||
<el-divider content-position="left">{{ $t('website.SSLConfig') }}</el-divider>
|
||||
@ -173,7 +173,7 @@ import { GetHTTPSConfig, ListSSL, SearchAcmeAccount, UpdateHTTPSConfig } from '@
|
||||
import { ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { Rules, checkNumberRange } from '@/global/form-rules';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { dateFormatSimple, getProvider, getAccountName } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import FileList from '@/components/file-list/index.vue';
|
||||
@ -204,7 +204,7 @@ const form = reactive({
|
||||
algorithm:
|
||||
'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED',
|
||||
SSLProtocol: ['TLSv1.3', 'TLSv1.2', 'TLSv1.1', 'TLSv1'],
|
||||
httpsPort: 443,
|
||||
httpsPort: '443',
|
||||
});
|
||||
const loading = ref(false);
|
||||
const ssls = ref();
|
||||
@ -222,7 +222,6 @@ const rules = ref({
|
||||
SSLProtocol: [Rules.requiredSelect],
|
||||
algorithm: [Rules.requiredInput],
|
||||
acmeAccountID: [Rules.requiredInput],
|
||||
httpsPort: [Rules.requiredInput, checkNumberRange(1, 65535)],
|
||||
});
|
||||
const resData = ref();
|
||||
const sslReq = reactive({
|
||||
@ -301,10 +300,8 @@ const get = () => {
|
||||
form.acmeAccountID = data.SSL.acmeAccountId;
|
||||
}
|
||||
form.hsts = data.hsts;
|
||||
if (data.httpsPort > 0) {
|
||||
form.httpsPort = data.httpsPort;
|
||||
}
|
||||
}
|
||||
listSSL();
|
||||
listAcmeAccount();
|
||||
});
|
||||
|
@ -262,21 +262,7 @@
|
||||
<span class="input-help">{{ $t('app.allowPortHelper') }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
|
||||
<el-input
|
||||
v-model.trim="website.primaryDomain"
|
||||
@input="changeAlias(website.primaryDomain)"
|
||||
:placeholder="$t('website.primaryDomainHelper')"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.otherDomains')" prop="otherDomains">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
v-model="website.otherDomains"
|
||||
:placeholder="$t('website.domainHelper')"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<DomainCreate v-model:form="website"></DomainCreate>
|
||||
<el-form-item prop="IPV6">
|
||||
<el-checkbox v-model="website.IPV6" :label="$t('website.ipv6')" size="large" />
|
||||
</el-form-item>
|
||||
@ -517,7 +503,7 @@ import { ElForm, FormInstance } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import Params from '@/views/app-store/detail/params/index.vue';
|
||||
import Check from '../check/index.vue';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { GetGroupList } from '@/api/modules/group';
|
||||
import { Group } from '@/api/interface/group';
|
||||
import { SearchRuntimes } from '@/api/modules/runtime';
|
||||
@ -528,6 +514,7 @@ import { GetAppService } from '@/api/modules/app';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { dateFormatSimple, getProvider, getAccountName } from '@/utils/util';
|
||||
import { Website } from '@/api/interface/website';
|
||||
import DomainCreate from '@/views/website/website/domain-create/index.vue';
|
||||
|
||||
const websiteForm = ref<FormInstance>();
|
||||
|
||||
@ -577,6 +564,7 @@ const initData = () => ({
|
||||
enableSSL: false,
|
||||
websiteSSLID: undefined,
|
||||
acmeAccountID: undefined,
|
||||
domains: [],
|
||||
});
|
||||
const website = ref(initData());
|
||||
const rules = ref<any>({
|
||||
@ -813,16 +801,6 @@ const changeAppType = (type: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
function isSubsetOfStrArray(primaryDomain: string, otherDomains: string): boolean {
|
||||
const arr: string[] = otherDomains.split('\n');
|
||||
for (const item of arr) {
|
||||
if (primaryDomain === item) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const openTaskLog = (taskID: string) => {
|
||||
taskLog.value.acceptParams(taskID);
|
||||
};
|
||||
@ -859,12 +837,6 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
const flag = isSubsetOfStrArray(website.value.primaryDomain, website.value.otherDomains);
|
||||
if (!flag) {
|
||||
MsgError(i18n.global.t('website.containWarn'));
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
PreCheck({})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
@ -897,6 +869,17 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => website.value.domains,
|
||||
(value) => {
|
||||
if (value.length > 0) {
|
||||
const firstDomain = value[0].domain;
|
||||
changeAlias(firstDomain);
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
const changeAlias = (value: string) => {
|
||||
const domain = value.split(':')[0];
|
||||
website.value.alias = domain;
|
||||
|
138
frontend/src/views/website/website/domain-create/index.vue
Normal file
138
frontend/src/views/website/website/domain-create/index.vue
Normal file
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form-item :label="$t('website.batchAdd')">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="20">
|
||||
<el-input
|
||||
class="p-w-400"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
v-model="create.domainStr"
|
||||
:placeholder="$t('website.domainHelper')"
|
||||
></el-input>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button @click="gengerateDomains" :disabled="create.domainStr == ''">
|
||||
{{ $t('website.generateDomain') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-row :gutter="20" v-for="(domain, index) of create.domains" :key="index">
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
:label="index == 0 ? $t('website.domain') : ''"
|
||||
:prop="`domains.${index}.domain`"
|
||||
:rules="rules.domain"
|
||||
>
|
||||
<el-input
|
||||
type="string"
|
||||
v-model="create.domains[index].domain"
|
||||
:placeholder="index > 0 ? $t('website.domain') : ''"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
:label="index == 0 ? $t('commons.table.port') : ''"
|
||||
:prop="`domains.${index}.port`"
|
||||
:rules="rules.port"
|
||||
>
|
||||
<el-input type="number" v-model.number="create.domains[index].port"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item :label="index == 0 ? 'SSL' : ''" prop="ssl">
|
||||
<el-checkbox
|
||||
v-model="create.domains[index].ssl"
|
||||
:disabled="create.domains[index].port == 80"
|
||||
></el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4" v-if="index == 0">
|
||||
<el-form-item :label="$t('commons.button.add') + $t('commons.table.port')">
|
||||
<el-button @click="addDomain">
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4" v-else>
|
||||
<el-form-item>
|
||||
<el-button @click="removeDomain(index)" link type="primary">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Rules, checkNumberRange } from '@/global/form-rules';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
const rules = ref({
|
||||
port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
|
||||
domain: [Rules.requiredInput, Rules.domain],
|
||||
domains: {
|
||||
type: Array,
|
||||
},
|
||||
});
|
||||
const initDomain = () => ({
|
||||
domain: '',
|
||||
port: 80,
|
||||
ssl: false,
|
||||
});
|
||||
const create = ref({
|
||||
websiteID: 0,
|
||||
domains: [initDomain()],
|
||||
domainStr: '',
|
||||
});
|
||||
|
||||
const addDomain = () => {
|
||||
create.value.domains.push(initDomain());
|
||||
};
|
||||
|
||||
const removeDomain = (index: number) => {
|
||||
create.value.domains.splice(index, 1);
|
||||
};
|
||||
|
||||
const gengerateDomains = () => {
|
||||
const lines = create.value.domainStr.split(/\r?\n/);
|
||||
lines.forEach((line) => {
|
||||
const [domain, port] = line.split(':');
|
||||
const exists = (domain: string, port: number): boolean => {
|
||||
return create.value.domains.some((info) => info.domain === domain && info.port === port);
|
||||
};
|
||||
if (exists(domain, port ? Number(port) : 80)) {
|
||||
return;
|
||||
}
|
||||
if (create.value.domains[0].domain == '') {
|
||||
create.value.domains[0].domain = domain;
|
||||
create.value.domains[0].port = port ? Number(port) : 80;
|
||||
} else {
|
||||
create.value.domains.push({
|
||||
domain,
|
||||
port: port ? Number(port) : 80,
|
||||
ssl: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleParams = () => {
|
||||
props.form.domains = create.value.domains;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleParams();
|
||||
});
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user