diff --git a/backend/app/api/v1/website.go b/backend/app/api/v1/website.go index 5d45d17d1..909fbfad1 100644 --- a/backend/app/api/v1/website.go +++ b/backend/app/api/v1/website.go @@ -100,7 +100,7 @@ func (b *BaseApi) RecoverWebsite(c *gin.Context) { } func (b *BaseApi) DeleteWebSite(c *gin.Context) { - var req dto.WebSiteDel + var req request.WebSiteDel if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return diff --git a/backend/app/dto/website.go b/backend/app/dto/website.go index 44f507277..6dab41f02 100644 --- a/backend/app/dto/website.go +++ b/backend/app/dto/website.go @@ -21,6 +21,7 @@ type WebSiteCreate struct { Alias string `json:"alias" validate:"required"` Remark string `json:"remark"` OtherDomains string `json:"otherDomains"` + Proxy string `json:"proxy"` AppType AppType `json:"appType"` AppInstall NewAppInstall `json:"appInstall"` AppID uint `json:"appID"` @@ -45,12 +46,6 @@ type NewAppInstall struct { Params map[string]interface{} `json:"params"` } -type WebSiteDel struct { - ID uint `json:"id"` - DeleteApp bool `json:"deleteApp"` - DeleteBackup bool `json:"deleteBackup"` -} - type WebSiteRecover struct { WebsiteName string `json:"websiteName" validate:"required"` Type string `json:"type" validate:"required"` diff --git a/backend/app/model/website.go b/backend/app/model/website.go index ea225990f..aef7ae3d0 100644 --- a/backend/app/model/website.go +++ b/backend/app/model/website.go @@ -14,6 +14,7 @@ type WebSite struct { AppInstallID uint `gorm:"type:integer" json:"appInstallId"` WebSiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"` WebSiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"` + Proxy string `gorm:"type:varchar(128);not null" json:"proxy"` Domains []WebSiteDomain `json:"domains"` WebSiteSSL WebSiteSSL `json:"webSiteSSL"` } diff --git a/backend/app/request/website.go b/backend/app/request/website.go index a5dee51c4..b5c9819d2 100644 --- a/backend/app/request/website.go +++ b/backend/app/request/website.go @@ -11,3 +11,10 @@ type WebsiteWafUpdate struct { Key string `json:"key" validate:"required"` Enable bool `json:"enable" validate:"required"` } + +type WebSiteDel struct { + ID uint `json:"id" validate:"required"` + DeleteApp bool `json:"deleteApp"` + DeleteBackup bool `json:"deleteBackup"` + ForceDelete bool `json:"forceDelete"` +} diff --git a/backend/app/service/website.go b/backend/app/service/website.go index 06694581e..46d7b405f 100644 --- a/backend/app/service/website.go +++ b/backend/app/service/website.go @@ -33,7 +33,7 @@ type IWebsiteService interface { Recover(req dto.WebSiteRecover) error RecoverByUpload(req dto.WebSiteRecoverByFile) error UpdateWebsite(req dto.WebSiteUpdate) error - DeleteWebSite(req dto.WebSiteDel) error + DeleteWebSite(req request.WebSiteDel) error GetWebsite(id uint) (dto.WebsiteDTO, error) CreateWebsiteDomain(create dto.WebSiteDomainCreate) (model.WebSiteDomain, error) GetWebsiteDomain(websiteId uint) ([]model.WebSiteDomain, error) @@ -88,9 +88,11 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error { AppInstallID: create.AppInstallID, WebSiteGroupID: create.WebSiteGroupID, Protocol: constant.ProtocolHTTP, + Proxy: create.Proxy, } - if create.Type == "deployment" { + switch create.Type { + case constant.Deployment: if create.AppType == dto.NewApp { install, err := ServiceGroupApp.Install(create.AppInstall.Name, create.AppInstall.AppDetailId, create.AppInstall.Params) if err != nil { @@ -98,7 +100,7 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error { } website.AppInstallID = install.ID } - } else { + case constant.Static: if err := createStaticHtml(website); err != nil { return err } @@ -240,12 +242,12 @@ func (w WebsiteService) GetWebsite(id uint) (dto.WebsiteDTO, error) { return res, nil } -func (w WebsiteService) DeleteWebSite(req dto.WebSiteDel) error { +func (w WebsiteService) DeleteWebSite(req request.WebSiteDel) error { website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID)) if err != nil { return err } - if err := delNginxConfig(website); err != nil { + if err := delNginxConfig(website, req.ForceDelete); err != nil { return err } tx, ctx := getTxAndContext() @@ -253,7 +255,7 @@ func (w WebsiteService) DeleteWebSite(req dto.WebSiteDel) error { if req.DeleteApp { websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(website.AppInstallID)) if len(websites) > 1 { - return errors.New("other website use this app") + return buserr.New(constant.ErrAppDelete) } appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID)) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { diff --git a/backend/app/service/website_utils.go b/backend/app/service/website_utils.go index 6eac28ff5..10c364bf3 100644 --- a/backend/app/service/website_utils.go +++ b/backend/app/service/website_utils.go @@ -74,7 +74,6 @@ func createStaticHtml(website *model.WebSite) error { } func createWebsiteFolder(nginxInstall model.AppInstall, website *model.WebSite) error { - nginxFolder := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name) siteFolder := path.Join(nginxFolder, "www", "sites", website.Alias) fileOp := files.NewFileOp() @@ -99,7 +98,6 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.WebSite) } func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) error { - nginxInstall, err := getAppInstallByKey("nginx") if err != nil { return err @@ -131,16 +129,19 @@ func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) e server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")}) server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")}) - if website.Type == "deployment" { + switch website.Type { + case constant.Deployment: appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID)) if err != nil { return err } proxy := fmt.Sprintf("http://127.0.0.1:%d", appInstall.HttpPort) server.UpdateRootProxy([]string{proxy}) - } else { + case constant.Static: server.UpdateRoot(path.Join("/www/sites", website.Alias)) server.UpdateRootLocation() + case constant.Proxy: + server.UpdateRootProxy([]string{website.Proxy}) } config.FilePath = configPath @@ -154,8 +155,7 @@ func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) e return opNginx(nginxInstall.ContainerName, constant.NginxReload) } -func delNginxConfig(website model.WebSite) error { - +func delNginxConfig(website model.WebSite, force bool) error { nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx")) if err != nil { return err @@ -178,11 +178,16 @@ func delNginxConfig(website model.WebSite) error { if err := fileOp.DeleteFile(configPath); err != nil { return err } - return opNginx(nginxInstall.ContainerName, "reload") + if err := opNginx(nginxInstall.ContainerName, "reload"); err != nil { + if force { + return nil + } + return err + } + return nil } func addListenAndServerName(website model.WebSite, ports []int, domains []string) error { - nginxFull, err := getNginxFull(&website) if err != nil { return nil @@ -203,7 +208,6 @@ func addListenAndServerName(website model.WebSite, ports []int, domains []string } func deleteListenAndServerName(website model.WebSite, ports []int, domains []string) error { - nginxFull, err := getNginxFull(&website) if err != nil { return nil @@ -280,7 +284,6 @@ func createPemFile(website model.WebSite, websiteSSL model.WebSiteSSL) error { } func applySSL(website model.WebSite, websiteSSL model.WebSiteSSL) error { - nginxFull, err := getNginxFull(&website) if err != nil { return nil @@ -398,7 +401,7 @@ func handleWebsiteBackup(backupType, baseDir, backupDir, domain, backupName stri return err } - if website.Type == "deployment" { + if website.Type == constant.Deployment { if err := mysqlOpration(&website, "backup", tmpDir); err != nil { return err } @@ -451,7 +454,7 @@ func handleWebsiteRecover(website *model.WebSite, fileDir string) error { return err } - if website.Type == "deployment" { + if website.Type == constant.Deployment { if err := mysqlOpration(website, "recover", fileDir); err != nil { return err } diff --git a/backend/constant/errs.go b/backend/constant/errs.go index a6d4230e3..450aeb9c4 100644 --- a/backend/constant/errs.go +++ b/backend/constant/errs.go @@ -59,6 +59,7 @@ var ( var ( ErrDomainIsExist = "ErrDomainIsExist" ErrAliasIsExist = "ErrAliasIsExist" + ErrAppDelete = "ErrAppDelete" ) //ssl diff --git a/backend/constant/website.go b/backend/constant/website.go index af04115fe..b0d90f742 100644 --- a/backend/constant/website.go +++ b/backend/constant/website.go @@ -14,3 +14,9 @@ const ( ProtocolHTTP = "HTTP" ProtocolHTTPS = "HTTPS" ) + +const ( + Deployment = "deployment" + Static = "static" + Proxy = "proxy" +) diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml index ec89164df..d3949877e 100644 --- a/backend/i18n/lang/en.yaml +++ b/backend/i18n/lang/en.yaml @@ -30,6 +30,7 @@ ErrFileToLarge: "file is too large" #website ErrDomainIsExist: "Domain is already exist" ErrAliasIsExist: "Alias is already exist" +ErrAppDelete: 'Other Website use this App' #ssl ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed" diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml index e43e2423e..1d51fe3c4 100644 --- a/backend/i18n/lang/zh.yaml +++ b/backend/i18n/lang/zh.yaml @@ -29,7 +29,7 @@ ErrFileToLarge: "文件超过10M,无法打开" #website ErrDomainIsExist: "域名已存在" ErrAliasIsExist: "代号已存在" -ErrAppDelete: '' +ErrAppDelete: '其他网站使用此应用,不能删除' #ssl ErrSSLCannotDelete: "证书正在被网站使用,无法删除" diff --git a/frontend/src/api/interface/website.ts b/frontend/src/api/interface/website.ts index 1f40e855c..1a1a967a9 100644 --- a/frontend/src/api/interface/website.ts +++ b/frontend/src/api/interface/website.ts @@ -54,6 +54,7 @@ export namespace WebSite { id: number; deleteApp: boolean; deleteBackup: boolean; + forceDelete: boolean; } export interface WebSiteCreateReq { @@ -65,6 +66,7 @@ export namespace WebSite { appInstallId: number; webSiteGroupId: number; otherDomains: string; + proxy: string; } export interface WebSiteUpdateReq { diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 5b4cb1991..a12c11061 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -104,7 +104,7 @@ export default { imageName: '支持英文、中文、数字、:.-_,长度1-30', complexityPassword: '请输入 8 位以上、必须含有字母、数字、特殊符号的密码', commonPassword: '请输入 6 位以上长度密码', - linuxName: '支持英文、数字、.-_,长度1-30', + linuxName: '支持英文、数字、._,长度1-30', email: '请输入正确的邮箱', number: '请输入正确的数字', ip: '请输入正确的 IP 地址', @@ -786,7 +786,7 @@ export default { otherDomains: '其他域名', type: '类型', static: '静态网站', - deployment: '反向代理', + deployment: '一键部署', supportUpType: '仅支持 tar.gz 文件', zipFormat: 'tar.gz 压缩包结构:test.tar.gz 压缩包内,必需包含 website.json 文件', proxy: '反向代理', @@ -868,6 +868,9 @@ export default { fileExtBlock: '文件扩展名黑名单', value: '值', enable: '开启', + proxyAddress: '代理地址', + proxyHelper: '例如: http://127.0.0.1:8080', + forceDelete: '强制删除', }, nginx: { serverNamesHashBucketSizeHelper: '服务器名字的hash表大小', diff --git a/frontend/src/views/website/website/create/index.vue b/frontend/src/views/website/website/create/index.vue index 6d22dec2d..03a37bc73 100644 --- a/frontend/src/views/website/website/create/index.vue +++ b/frontend/src/views/website/website/create/index.vue @@ -1,17 +1,24 @@