mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08:06 +08:00
feat: 增加网站创建功能
This commit is contained in:
parent
a1ac689a5e
commit
ef789cdfea
@ -10,7 +10,7 @@
|
|||||||
"name": "服务器"
|
"name": "服务器"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "Datastore",
|
"key": "Database",
|
||||||
"name": "数据库"
|
"name": "数据库"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -18,7 +18,7 @@
|
|||||||
{
|
{
|
||||||
"key": "mysql5.7",
|
"key": "mysql5.7",
|
||||||
"name": "Mysql5.7",
|
"name": "Mysql5.7",
|
||||||
"tags": ["Datastore"],
|
"tags": ["Database"],
|
||||||
"versions": ["5.7.39"],
|
"versions": ["5.7.39"],
|
||||||
"short_desc": "常用关系型数据库",
|
"short_desc": "常用关系型数据库",
|
||||||
"icon": "mysql.png",
|
"icon": "mysql.png",
|
||||||
@ -32,7 +32,7 @@
|
|||||||
{
|
{
|
||||||
"key": "mysql8.0",
|
"key": "mysql8.0",
|
||||||
"name": "Mysql8.0",
|
"name": "Mysql8.0",
|
||||||
"tags": ["Datastore"],
|
"tags": ["Database"],
|
||||||
"versions": ["8.0.30"],
|
"versions": ["8.0.30"],
|
||||||
"short_desc": "常用关系型数据库",
|
"short_desc": "常用关系型数据库",
|
||||||
"icon": "mysql.png",
|
"icon": "mysql.png",
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"icon": "wordpress.png",
|
"icon": "wordpress.png",
|
||||||
"author": "Wordpress",
|
"author": "Wordpress",
|
||||||
"type": "website",
|
"type": "website",
|
||||||
"required": ["mysql"],
|
"required": ["mysql8.0"],
|
||||||
"limit": 0,
|
"limit": 0,
|
||||||
"crossVersionUpdate": true,
|
"crossVersionUpdate": true,
|
||||||
"source": "http://wordpress.org/"
|
"source": "http://wordpress.org/"
|
||||||
@ -74,7 +74,7 @@
|
|||||||
{
|
{
|
||||||
"key": "redis",
|
"key": "redis",
|
||||||
"name": "redis",
|
"name": "redis",
|
||||||
"tags": ["Datastore"],
|
"tags": ["Database"],
|
||||||
"versions": ["7.0.5","6.0.16"],
|
"versions": ["7.0.5","6.0.16"],
|
||||||
"short_desc": "缓存数据库",
|
"short_desc": "缓存数据库",
|
||||||
"icon": "redis.png",
|
"icon": "redis.png",
|
||||||
|
99
apps/nginx/1.23.1/conf/mime.types
Normal file
99
apps/nginx/1.23.1/conf/mime.types
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
types {
|
||||||
|
text/html html htm shtml;
|
||||||
|
text/css css;
|
||||||
|
text/xml xml;
|
||||||
|
image/gif gif;
|
||||||
|
image/jpeg jpeg jpg;
|
||||||
|
application/javascript js;
|
||||||
|
application/atom+xml atom;
|
||||||
|
application/rss+xml rss;
|
||||||
|
|
||||||
|
text/mathml mml;
|
||||||
|
text/plain txt;
|
||||||
|
text/vnd.sun.j2me.app-descriptor jad;
|
||||||
|
text/vnd.wap.wml wml;
|
||||||
|
text/x-component htc;
|
||||||
|
|
||||||
|
image/avif avif;
|
||||||
|
image/png png;
|
||||||
|
image/svg+xml svg svgz;
|
||||||
|
image/tiff tif tiff;
|
||||||
|
image/vnd.wap.wbmp wbmp;
|
||||||
|
image/webp webp;
|
||||||
|
image/x-icon ico;
|
||||||
|
image/x-jng jng;
|
||||||
|
image/x-ms-bmp bmp;
|
||||||
|
|
||||||
|
font/woff woff;
|
||||||
|
font/woff2 woff2;
|
||||||
|
|
||||||
|
application/java-archive jar war ear;
|
||||||
|
application/json json;
|
||||||
|
application/mac-binhex40 hqx;
|
||||||
|
application/msword doc;
|
||||||
|
application/pdf pdf;
|
||||||
|
application/postscript ps eps ai;
|
||||||
|
application/rtf rtf;
|
||||||
|
application/vnd.apple.mpegurl m3u8;
|
||||||
|
application/vnd.google-earth.kml+xml kml;
|
||||||
|
application/vnd.google-earth.kmz kmz;
|
||||||
|
application/vnd.ms-excel xls;
|
||||||
|
application/vnd.ms-fontobject eot;
|
||||||
|
application/vnd.ms-powerpoint ppt;
|
||||||
|
application/vnd.oasis.opendocument.graphics odg;
|
||||||
|
application/vnd.oasis.opendocument.presentation odp;
|
||||||
|
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||||
|
application/vnd.oasis.opendocument.text odt;
|
||||||
|
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||||
|
pptx;
|
||||||
|
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||||
|
xlsx;
|
||||||
|
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||||
|
docx;
|
||||||
|
application/vnd.wap.wmlc wmlc;
|
||||||
|
application/wasm wasm;
|
||||||
|
application/x-7z-compressed 7z;
|
||||||
|
application/x-cocoa cco;
|
||||||
|
application/x-java-archive-diff jardiff;
|
||||||
|
application/x-java-jnlp-file jnlp;
|
||||||
|
application/x-makeself run;
|
||||||
|
application/x-perl pl pm;
|
||||||
|
application/x-pilot prc pdb;
|
||||||
|
application/x-rar-compressed rar;
|
||||||
|
application/x-redhat-package-manager rpm;
|
||||||
|
application/x-sea sea;
|
||||||
|
application/x-shockwave-flash swf;
|
||||||
|
application/x-stuffit sit;
|
||||||
|
application/x-tcl tcl tk;
|
||||||
|
application/x-x509-ca-cert der pem crt;
|
||||||
|
application/x-xpinstall xpi;
|
||||||
|
application/xhtml+xml xhtml;
|
||||||
|
application/xspf+xml xspf;
|
||||||
|
application/zip zip;
|
||||||
|
|
||||||
|
application/octet-stream bin exe dll;
|
||||||
|
application/octet-stream deb;
|
||||||
|
application/octet-stream dmg;
|
||||||
|
application/octet-stream iso img;
|
||||||
|
application/octet-stream msi msp msm;
|
||||||
|
|
||||||
|
audio/midi mid midi kar;
|
||||||
|
audio/mpeg mp3;
|
||||||
|
audio/ogg ogg;
|
||||||
|
audio/x-m4a m4a;
|
||||||
|
audio/x-realaudio ra;
|
||||||
|
|
||||||
|
video/3gpp 3gpp 3gp;
|
||||||
|
video/mp2t ts;
|
||||||
|
video/mp4 mp4;
|
||||||
|
video/mpeg mpeg mpg;
|
||||||
|
video/quicktime mov;
|
||||||
|
video/webm webm;
|
||||||
|
video/x-flv flv;
|
||||||
|
video/x-m4v m4v;
|
||||||
|
video/x-mng mng;
|
||||||
|
video/x-ms-asf asx asf;
|
||||||
|
video/x-ms-wmv wmv;
|
||||||
|
video/x-msvideo avi;
|
||||||
|
}
|
@ -11,7 +11,7 @@ events {
|
|||||||
|
|
||||||
|
|
||||||
http {
|
http {
|
||||||
include /etc/nginx/mime.types;
|
include mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
||||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
@ -23,14 +23,4 @@ http {
|
|||||||
keepalive_timeout 65;
|
keepalive_timeout 65;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
include /etc/nginx/conf.d/*.conf;
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name 127.0.0.1;
|
|
||||||
allow 127.0.0.1;
|
|
||||||
location /nginx_status {
|
|
||||||
stub_status on;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -10,10 +10,8 @@ services:
|
|||||||
- ${PANEL_APP_PORT_HTTPS}:443
|
- ${PANEL_APP_PORT_HTTPS}:443
|
||||||
volumes:
|
volumes:
|
||||||
- ./conf/nginx.conf:/etc/nginx/nginx.conf
|
- ./conf/nginx.conf:/etc/nginx/nginx.conf
|
||||||
- ./www:/home/www
|
|
||||||
- ./log:/var/log/nginx
|
- ./log:/var/log/nginx
|
||||||
- ./conf/conf.d:/etc/nginx/conf.d/
|
- ./conf/conf.d:/etc/nginx/conf.d/
|
||||||
- ./html:/usr/share/nginx/html
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
1panel:
|
1panel:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"formFields": [
|
"formFields": [
|
||||||
{
|
{
|
||||||
"type": "service",
|
"type": "service",
|
||||||
"key": "mysql",
|
"key": "mysql8.0",
|
||||||
"labelZh": "数据库服务",
|
"labelZh": "数据库服务",
|
||||||
"labelEn": "Database Service",
|
"labelEn": "Database Service",
|
||||||
"required": true,
|
"required": true,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"formFields": [
|
"formFields": [
|
||||||
{
|
{
|
||||||
"type": "service",
|
"type": "service",
|
||||||
"key": "mysql",
|
"key": "mysql8.0",
|
||||||
"labelZh": "数据库服务",
|
"labelZh": "数据库服务",
|
||||||
"labelEn": "Database Service",
|
"labelEn": "Database Service",
|
||||||
"required": true,
|
"required": true,
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *BaseApi) SearchApp(c *gin.Context) {
|
func (b *BaseApi) SearchApp(c *gin.Context) {
|
||||||
@ -98,16 +98,26 @@ func (b *BaseApi) SearchInstalled(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
total, list, err := appService.PageInstalled(req)
|
if !reflect.DeepEqual(req.PageInfo, dto.PageInfo{}) {
|
||||||
if err != nil {
|
total, list, err := appService.PageInstalled(req)
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
if err != nil {
|
||||||
return
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
helper.SuccessWithData(c, dto.PageResult{
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
Items: list,
|
Items: list,
|
||||||
Total: total,
|
Total: total,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
list, err := appService.SearchInstalled(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseApi) SearchInstalledBackup(c *gin.Context) {
|
func (b *BaseApi) SearchInstalledBackup(c *gin.Context) {
|
||||||
|
@ -25,11 +25,13 @@ var (
|
|||||||
|
|
||||||
hostService = service.ServiceGroupApp.HostService
|
hostService = service.ServiceGroupApp.HostService
|
||||||
groupService = service.ServiceGroupApp.GroupService
|
groupService = service.ServiceGroupApp.GroupService
|
||||||
commandService = service.ServiceGroupApp.CommandService
|
|
||||||
fileService = service.ServiceGroupApp.FileService
|
fileService = service.ServiceGroupApp.FileService
|
||||||
|
|
||||||
settingService = service.ServiceGroupApp.SettingService
|
settingService = service.ServiceGroupApp.SettingService
|
||||||
backupService = service.ServiceGroupApp.BackupService
|
backupService = service.ServiceGroupApp.BackupService
|
||||||
|
|
||||||
operationService = service.ServiceGroupApp.OperationService
|
operationService = service.ServiceGroupApp.OperationService
|
||||||
|
commandService = service.ServiceGroupApp.CommandService
|
||||||
|
websiteGroupService = service.ServiceGroupApp.WebsiteGroupService
|
||||||
|
websiteService = service.ServiceGroupApp.WebsiteService
|
||||||
)
|
)
|
||||||
|
24
backend/app/api/v1/website.go
Normal file
24
backend/app/api/v1/website.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
||||||
|
|
||||||
|
var req dto.WebSiteCreate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := websiteService.CreateWebsite(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
17
backend/app/api/v1/website_group.go
Normal file
17
backend/app/api/v1/website_group.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *BaseApi) GetGroups(c *gin.Context) {
|
||||||
|
|
||||||
|
list, err := websiteGroupService.GetGroups()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
@ -48,6 +48,7 @@ type AppInstalled struct {
|
|||||||
|
|
||||||
type AppInstalledRequest struct {
|
type AppInstalledRequest struct {
|
||||||
PageInfo
|
PageInfo
|
||||||
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppBackupRequest struct {
|
type AppBackupRequest struct {
|
||||||
|
16
backend/app/dto/website.go
Normal file
16
backend/app/dto/website.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type WebPage struct {
|
||||||
|
PageInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebSiteCreate struct {
|
||||||
|
PrimaryDomain string `json:"primaryDomain"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
Domains []string `json:"domains"`
|
||||||
|
AppType string `json:"appType"`
|
||||||
|
AppInstallID uint `json:"appInstallID"`
|
||||||
|
WebSiteGroupID uint `json:"webSiteGroupID"`
|
||||||
|
}
|
10
backend/app/dto/website_group.go
Normal file
10
backend/app/dto/website_group.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type WebSiteGroupCreateReq struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebSiteGroupUpdateReq struct {
|
||||||
|
ID uint
|
||||||
|
Name string
|
||||||
|
}
|
16
backend/app/model/website.go
Normal file
16
backend/app/model/website.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type WebSite struct {
|
||||||
|
BaseModel
|
||||||
|
PrimaryDomain string `gorm:"type:varchar(128);not null" json:"primaryDomain"`
|
||||||
|
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||||
|
Alias string `gorm:"type:varchar(128);not null" json:"alias"`
|
||||||
|
Remark string `gorm:"type:longtext;" json:"remark"`
|
||||||
|
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
||||||
|
ExpireDate time.Time `json:"expireDate"`
|
||||||
|
AppInstallID uint `gorm:"type:integer" json:"appInstallID"`
|
||||||
|
WebSiteGroupID uint `gorm:"type:integer" json:"webSiteGroupID"`
|
||||||
|
WebSiteSSLID uint `gorm:"type:integer" json:"webSiteSSLID"`
|
||||||
|
}
|
8
backend/app/model/website_domain.go
Normal file
8
backend/app/model/website_domain.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type WebSiteDomain struct {
|
||||||
|
BaseModel
|
||||||
|
WebSiteID uint `gorm:"type:varchar(64);not null" json:"web_site_id"`
|
||||||
|
Domain string `gorm:"type:varchar(256);not null" json:"domain"`
|
||||||
|
Port int `gorm:"type:integer" json:"port"`
|
||||||
|
}
|
7
backend/app/model/website_group.go
Normal file
7
backend/app/model/website_group.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type WebSiteGroup struct {
|
||||||
|
BaseModel
|
||||||
|
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||||
|
Default bool `json:"default"`
|
||||||
|
}
|
5
backend/app/model/website_ssl.go
Normal file
5
backend/app/model/website_ssl.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type WebSiteSSL struct {
|
||||||
|
BaseModel
|
||||||
|
}
|
@ -16,6 +16,12 @@ func (a AppRepo) WithKey(key string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppRepo) WithType(typeStr string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("type = ?", typeStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppRepo) Page(page, size int, opts ...DBOption) (int64, []model.App, error) {
|
func (a AppRepo) Page(page, size int, opts ...DBOption) (int64, []model.App, error) {
|
||||||
var apps []model.App
|
var apps []model.App
|
||||||
db := getDb(opts...).Model(&model.App{})
|
db := getDb(opts...).Model(&model.App{})
|
||||||
|
@ -25,6 +25,13 @@ func (a AppInstallRepo) WithAppId(appId uint) DBOption {
|
|||||||
return g.Where("app_id = ?", appId)
|
return g.Where("app_id = ?", appId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppInstallRepo) WithAppIdsIn(appIds []uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("app_id in (?)", appIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppInstallRepo) WithStatus(status string) DBOption {
|
func (a AppInstallRepo) WithStatus(status string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("status = ?", status)
|
return g.Where("status = ?", status)
|
||||||
|
@ -3,7 +3,6 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,24 +16,16 @@ func (d DatabaseRepo) ByAppInstallId(installId uint) DBOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d DatabaseRepo) Create(ctx context.Context, database *model.AppDatabase) error {
|
func (d DatabaseRepo) Create(ctx context.Context, database *model.AppDatabase) error {
|
||||||
db := ctx.Value("db").(*gorm.DB).Model(&model.AppDatabase{})
|
return getTx(ctx).Model(&model.AppDatabase{}).Create(&database).Error
|
||||||
return db.Create(&database).Error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DatabaseRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
|
func (d DatabaseRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
|
||||||
db := ctx.Value("db").(*gorm.DB).Model(&model.AppDatabase{})
|
return getTx(ctx, opts...).Model(&model.AppDatabase{}).Delete(&model.AppDatabase{}).Error
|
||||||
for _, opt := range opts {
|
|
||||||
db = opt(db)
|
|
||||||
}
|
|
||||||
return db.Delete(&model.AppDatabase{}).Error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DatabaseRepo) GetBy(opts ...DBOption) ([]model.AppDatabase, error) {
|
func (d DatabaseRepo) GetBy(opts ...DBOption) ([]model.AppDatabase, error) {
|
||||||
db := global.DB.Model(model.AppDatabase{})
|
db := getDb(opts...)
|
||||||
var databases []model.AppDatabase
|
var databases []model.AppDatabase
|
||||||
for _, opt := range opts {
|
|
||||||
db = opt(db)
|
|
||||||
}
|
|
||||||
err := db.Find(&databases).Error
|
err := db.Find(&databases).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -43,11 +34,8 @@ func (d DatabaseRepo) GetBy(opts ...DBOption) ([]model.AppDatabase, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d DatabaseRepo) GetFirst(opts ...DBOption) (model.AppDatabase, error) {
|
func (d DatabaseRepo) GetFirst(opts ...DBOption) (model.AppDatabase, error) {
|
||||||
db := global.DB.Model(model.AppDatabase{})
|
db := getDb(opts...)
|
||||||
var database model.AppDatabase
|
var database model.AppDatabase
|
||||||
for _, opt := range opts {
|
|
||||||
db = opt(db)
|
|
||||||
}
|
|
||||||
err := db.Find(&database).Error
|
err := db.Find(&database).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return database, err
|
return database, err
|
||||||
|
@ -2,7 +2,6 @@ package repo
|
|||||||
|
|
||||||
type RepoGroup struct {
|
type RepoGroup struct {
|
||||||
CommonRepo
|
CommonRepo
|
||||||
|
|
||||||
AppRepo
|
AppRepo
|
||||||
AppTagRepo
|
AppTagRepo
|
||||||
TagRepo
|
TagRepo
|
||||||
@ -11,22 +10,19 @@ type RepoGroup struct {
|
|||||||
AppInstallResourceRpo
|
AppInstallResourceRpo
|
||||||
DatabaseRepo
|
DatabaseRepo
|
||||||
AppInstallBackupRepo
|
AppInstallBackupRepo
|
||||||
|
|
||||||
ImageRepoRepo
|
ImageRepoRepo
|
||||||
ComposeTemplateRepo
|
ComposeTemplateRepo
|
||||||
|
|
||||||
MysqlRepo
|
MysqlRepo
|
||||||
|
|
||||||
CronjobRepo
|
CronjobRepo
|
||||||
|
|
||||||
HostRepo
|
HostRepo
|
||||||
CommandRepo
|
CommandRepo
|
||||||
GroupRepo
|
GroupRepo
|
||||||
|
|
||||||
SettingRepo
|
SettingRepo
|
||||||
BackupRepo
|
BackupRepo
|
||||||
|
|
||||||
OperationRepo
|
OperationRepo
|
||||||
|
WebSiteRepo
|
||||||
|
WebSiteDomainRepo
|
||||||
|
WebSiteGroupRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
var RepoGroupApp = new(RepoGroup)
|
var RepoGroupApp = new(RepoGroup)
|
||||||
|
45
backend/app/repo/website.go
Normal file
45
backend/app/repo/website.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebSiteRepo struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebSite, error) {
|
||||||
|
var websites []model.WebSite
|
||||||
|
db := getDb(opts...).Model(&model.WebSite{})
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Debug().Limit(size).Offset(size * (page - 1)).Find(&websites).Error
|
||||||
|
return count, websites, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteRepo) GetFirst(opts ...DBOption) (model.WebSite, error) {
|
||||||
|
var website model.WebSite
|
||||||
|
db := getDb(opts...).Model(&model.WebSite{})
|
||||||
|
if err := db.First(&website).Error; err != nil {
|
||||||
|
return website, err
|
||||||
|
}
|
||||||
|
return website, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteRepo) GetBy(opts ...DBOption) ([]model.WebSite, error) {
|
||||||
|
var websites []model.WebSite
|
||||||
|
db := getDb(opts...).Model(&model.WebSite{})
|
||||||
|
if err := db.Find(&websites).Error; err != nil {
|
||||||
|
return websites, err
|
||||||
|
}
|
||||||
|
return websites, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteRepo) Create(ctx context.Context, app *model.WebSite) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Create(app).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteRepo) Save(ctx context.Context, app *model.WebSite) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Save(app).Error
|
||||||
|
}
|
49
backend/app/repo/website_domain.go
Normal file
49
backend/app/repo/website_domain.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebSiteDomainRepo struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteDomainRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebSiteDomain, error) {
|
||||||
|
var domains []model.WebSiteDomain
|
||||||
|
db := getDb(opts...).Model(&model.WebSiteDomain{})
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Debug().Limit(size).Offset(size * (page - 1)).Find(&domains).Error
|
||||||
|
return count, domains, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteDomainRepo) GetFirst(opts ...DBOption) (model.WebSiteDomain, error) {
|
||||||
|
var domain model.WebSiteDomain
|
||||||
|
db := getDb(opts...).Model(&model.WebSiteDomain{})
|
||||||
|
if err := db.First(&domain).Error; err != nil {
|
||||||
|
return domain, err
|
||||||
|
}
|
||||||
|
return domain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteDomainRepo) GetBy(opts ...DBOption) ([]model.WebSiteDomain, error) {
|
||||||
|
var domains []model.WebSiteDomain
|
||||||
|
db := getDb(opts...).Model(&model.WebSiteDomain{})
|
||||||
|
if err := db.Find(&domains).Error; err != nil {
|
||||||
|
return domains, err
|
||||||
|
}
|
||||||
|
return domains, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteDomainRepo) BatchCreate(ctx context.Context, domains []model.WebSiteDomain) error {
|
||||||
|
return getTx(ctx).Model(&model.WebSiteDomain{}).Create(&domains).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteDomainRepo) Create(ctx context.Context, app *model.WebSiteDomain) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Create(app).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteDomainRepo) Save(ctx context.Context, app *model.WebSiteDomain) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Save(app).Error
|
||||||
|
}
|
39
backend/app/repo/website_group.go
Normal file
39
backend/app/repo/website_group.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebSiteGroupRepo struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteGroupRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebSiteGroup, error) {
|
||||||
|
var groups []model.WebSiteGroup
|
||||||
|
db := getDb(opts...).Model(&model.WebSiteGroup{})
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Debug().Limit(size).Offset(size * (page - 1)).Find(&groups).Error
|
||||||
|
return count, groups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteGroupRepo) GetBy(opts ...DBOption) ([]model.WebSiteGroup, error) {
|
||||||
|
var groups []model.WebSiteGroup
|
||||||
|
db := getDb(opts...).Model(&model.WebSiteGroup{})
|
||||||
|
if err := db.Find(&groups).Error; err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteGroupRepo) Create(app *model.WebSiteGroup) error {
|
||||||
|
return getDb().Omit(clause.Associations).Create(app).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteGroupRepo) Save(app *model.WebSiteGroup) error {
|
||||||
|
return getDb().Omit(clause.Associations).Save(app).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebSiteGroupRepo) DeleteBy(opts ...DBOption) error {
|
||||||
|
return getDb(opts...).Delete(&model.WebSiteGroup{}).Error
|
||||||
|
}
|
@ -127,6 +127,40 @@ func (a AppService) PageInstalled(req dto.AppInstalledRequest) (int64, []dto.App
|
|||||||
return total, installDTOs, nil
|
return total, installDTOs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppService) SearchInstalled(req dto.AppInstalledRequest) ([]dto.AppInstalled, error) {
|
||||||
|
var installs []model.AppInstall
|
||||||
|
var err error
|
||||||
|
if req.Type != "" {
|
||||||
|
apps, err := appRepo.GetBy(appRepo.WithType(req.Type))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var ids []uint
|
||||||
|
for _, app := range apps {
|
||||||
|
ids = append(ids, app.ID)
|
||||||
|
}
|
||||||
|
installs, err = appInstallRepo.GetBy(appInstallRepo.WithAppIdsIn(ids))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
installs, err = appInstallRepo.GetBy()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var installDTOs []dto.AppInstalled
|
||||||
|
for _, in := range installs {
|
||||||
|
installDto := dto.AppInstalled{
|
||||||
|
AppInstall: in,
|
||||||
|
}
|
||||||
|
installDTOs = append(installDTOs, installDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
return installDTOs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppService) GetAppDetail(appId uint, version string) (dto.AppDetailDTO, error) {
|
func (a AppService) GetAppDetail(appId uint, version string) (dto.AppDetailDTO, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -26,6 +26,8 @@ type ServiceGroup struct {
|
|||||||
BackupService
|
BackupService
|
||||||
|
|
||||||
OperationService
|
OperationService
|
||||||
|
WebsiteGroupService
|
||||||
|
WebsiteService
|
||||||
}
|
}
|
||||||
|
|
||||||
var ServiceGroupApp = new(ServiceGroup)
|
var ServiceGroupApp = new(ServiceGroup)
|
||||||
@ -57,4 +59,7 @@ var (
|
|||||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
backupRepo = repo.RepoGroupApp.BackupRepo
|
||||||
|
|
||||||
operationRepo = repo.RepoGroupApp.OperationRepo
|
operationRepo = repo.RepoGroupApp.OperationRepo
|
||||||
|
websiteRepo = repo.RepoGroupApp.WebSiteRepo
|
||||||
|
websiteGroupRepo = repo.RepoGroupApp.WebSiteGroupRepo
|
||||||
|
websiteDomainRepo = repo.RepoGroupApp.WebSiteDomainRepo
|
||||||
)
|
)
|
||||||
|
@ -2,16 +2,18 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dbStr string
|
type DBContext string
|
||||||
|
|
||||||
|
const (
|
||||||
|
DB DBContext = "db"
|
||||||
|
)
|
||||||
|
|
||||||
func getTxAndContext() (tx *gorm.DB, ctx context.Context) {
|
func getTxAndContext() (tx *gorm.DB, ctx context.Context) {
|
||||||
db := dbStr("db")
|
|
||||||
tx = global.DB.Begin()
|
tx = global.DB.Begin()
|
||||||
ctx = context.WithValue(context.Background(), db, tx)
|
ctx = context.WithValue(context.Background(), DB, tx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
60
backend/app/service/website.go
Normal file
60
backend/app/service/website.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebsiteService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
|
||||||
|
|
||||||
|
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
||||||
|
|
||||||
|
website := &model.WebSite{
|
||||||
|
PrimaryDomain: create.PrimaryDomain,
|
||||||
|
Type: create.Type,
|
||||||
|
Alias: create.Alias,
|
||||||
|
Remark: create.Remark,
|
||||||
|
Status: constant.WebRunning,
|
||||||
|
ExpireDate: defaultDate,
|
||||||
|
AppInstallID: create.AppInstallID,
|
||||||
|
WebSiteGroupID: create.WebSiteGroupID,
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, ctx := getTxAndContext()
|
||||||
|
if err := websiteRepo.Create(ctx, website); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var domains []model.WebSiteDomain
|
||||||
|
domains = append(domains, model.WebSiteDomain{Domain: website.PrimaryDomain, WebSiteID: website.ID, Port: 80})
|
||||||
|
for _, domain := range create.Domains {
|
||||||
|
domainModel, err := getDomain(domain, website.ID)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if reflect.DeepEqual(domainModel, model.WebSiteDomain{}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
domains = append(domains, domainModel)
|
||||||
|
}
|
||||||
|
if len(domains) > 0 {
|
||||||
|
if err := websiteDomainRepo.BatchCreate(ctx, domains); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := configDefaultNginx(*website, domains); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
return nil
|
||||||
|
}
|
32
backend/app/service/website_group.go
Normal file
32
backend/app/service/website_group.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebsiteGroupService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebsiteGroupService) CreateGroup(create dto.WebSiteGroupCreateReq) error {
|
||||||
|
return websiteGroupRepo.Create(&model.WebSiteGroup{
|
||||||
|
Name: create.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebsiteGroupService) GetGroups() ([]model.WebSiteGroup, error) {
|
||||||
|
return websiteGroupRepo.GetBy()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebsiteGroupService) UpdateGroup(update dto.WebSiteGroupUpdateReq) error {
|
||||||
|
return websiteGroupRepo.Save(&model.WebSiteGroup{
|
||||||
|
BaseModel: model.BaseModel{
|
||||||
|
ID: update.ID,
|
||||||
|
},
|
||||||
|
Name: update.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WebsiteGroupService) DeleteGroup(id uint) error {
|
||||||
|
return websiteGroupRepo.DeleteBy(commonRepo.WithByID(id))
|
||||||
|
}
|
92
backend/app/service/website_utils.go
Normal file
92
backend/app/service/website_utils.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
|
||||||
|
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDomain(domainStr string, websiteID uint) (model.WebSiteDomain, error) {
|
||||||
|
domain := model.WebSiteDomain{
|
||||||
|
WebSiteID: websiteID,
|
||||||
|
}
|
||||||
|
domainArray := strings.Split(domainStr, ":")
|
||||||
|
if len(domainArray) == 1 {
|
||||||
|
domain.Domain = domainArray[0]
|
||||||
|
return domain, nil
|
||||||
|
}
|
||||||
|
if len(domainArray) > 1 {
|
||||||
|
domain.Domain = domainArray[0]
|
||||||
|
portStr := domainArray[1]
|
||||||
|
portN, err := strconv.Atoi(portStr)
|
||||||
|
if err != nil {
|
||||||
|
return model.WebSiteDomain{}, err
|
||||||
|
}
|
||||||
|
domain.Port = portN
|
||||||
|
return domain, nil
|
||||||
|
}
|
||||||
|
return model.WebSiteDomain{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configDefaultNginx(website model.WebSite, domains []model.WebSiteDomain) error {
|
||||||
|
|
||||||
|
nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nginxInstall, err := appInstallRepo.GetFirst(appInstallRepo.WithAppId(nginxApp.ID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nginxFileName := website.PrimaryDomain + ".conf"
|
||||||
|
configPath := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name, "conf", "conf.d", nginxFileName)
|
||||||
|
|
||||||
|
nginxContent := string(nginx_conf.WebsiteDefault)
|
||||||
|
config := parser.NewStringParser(nginxContent).Parse()
|
||||||
|
servers := config.FindServers()
|
||||||
|
if len(servers) == 0 {
|
||||||
|
return errors.New("nginx config is not valid")
|
||||||
|
}
|
||||||
|
server := servers[0]
|
||||||
|
var serverNames []string
|
||||||
|
for _, domain := range domains {
|
||||||
|
serverNames = append(serverNames, domain.Domain)
|
||||||
|
server.UpdateListen(string(rune(domain.Port)), false)
|
||||||
|
}
|
||||||
|
server.UpdateServerName(serverNames)
|
||||||
|
proxy := fmt.Sprintf("%s:%d", appInstall.ServiceName, appInstall.HttpPort)
|
||||||
|
server.UpdateRootProxy([]string{proxy})
|
||||||
|
|
||||||
|
config.FilePath = configPath
|
||||||
|
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := opNginx(nginxInstall.ContainerName, "check"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return opNginx(nginxInstall.ContainerName, "reload")
|
||||||
|
}
|
||||||
|
|
||||||
|
func opNginx(containerName, operate string) error {
|
||||||
|
nginxCmd := fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -s reload")
|
||||||
|
if operate == "check" {
|
||||||
|
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
||||||
|
}
|
||||||
|
if _, err := cmd.Exec(nginxCmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
11
backend/constant/website.go
Normal file
11
backend/constant/website.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
WebRunning = "Running"
|
||||||
|
WebStopped = "Stopped"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DateLayout = "2006-01-02"
|
||||||
|
DefaultDate = "1970-01-01"
|
||||||
|
)
|
@ -17,6 +17,7 @@ func Init() {
|
|||||||
migrations.AddTableCronjob,
|
migrations.AddTableCronjob,
|
||||||
migrations.AddTableApp,
|
migrations.AddTableApp,
|
||||||
migrations.AddTableImageRepo,
|
migrations.AddTableImageRepo,
|
||||||
|
migrations.AddTableWebsite,
|
||||||
migrations.AddTableDatabaseMysql,
|
migrations.AddTableDatabaseMysql,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
|
@ -177,3 +177,20 @@ var AddTableDatabaseMysql = &gormigrate.Migration{
|
|||||||
return tx.AutoMigrate(&model.DatabaseMysql{})
|
return tx.AutoMigrate(&model.DatabaseMysql{})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var AddTableWebsite = &gormigrate.Migration{
|
||||||
|
ID: "20201009-add-table-website",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.WebSite{}, &model.WebSiteDomain{}, &model.WebSiteGroup{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
item := &model.WebSiteGroup{
|
||||||
|
Name: "默认分组",
|
||||||
|
Default: true,
|
||||||
|
}
|
||||||
|
if err := tx.Create(item).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -79,6 +79,8 @@ func Routers() *gin.Engine {
|
|||||||
systemRouter.InitCronjobRouter(PrivateGroup)
|
systemRouter.InitCronjobRouter(PrivateGroup)
|
||||||
systemRouter.InitSettingRouter(PrivateGroup)
|
systemRouter.InitSettingRouter(PrivateGroup)
|
||||||
systemRouter.InitAppRouter(PrivateGroup)
|
systemRouter.InitAppRouter(PrivateGroup)
|
||||||
|
systemRouter.InitWebsiteRouter(PrivateGroup)
|
||||||
|
systemRouter.InitWebsiteGroupRouter(PrivateGroup)
|
||||||
systemRouter.InitDatabaseRouter(PrivateGroup)
|
systemRouter.InitDatabaseRouter(PrivateGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ type RouterGroup struct {
|
|||||||
CronjobRouter
|
CronjobRouter
|
||||||
SettingRouter
|
SettingRouter
|
||||||
AppRouter
|
AppRouter
|
||||||
|
WebsiteRouter
|
||||||
|
WebsiteGroupRouter
|
||||||
DatabaseRouter
|
DatabaseRouter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
backend/router/ro_website.go
Normal file
20
backend/router/ro_website.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/middleware"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebsiteRouter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
||||||
|
groupRouter := Router.Group("websites")
|
||||||
|
groupRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
|
||||||
|
|
||||||
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
|
{
|
||||||
|
groupRouter.POST("", baseApi.CreateWebsite)
|
||||||
|
}
|
||||||
|
}
|
20
backend/router/ro_website_group.go
Normal file
20
backend/router/ro_website_group.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/middleware"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebsiteGroupRouter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebsiteGroupRouter) InitWebsiteGroupRouter(Router *gin.RouterGroup) {
|
||||||
|
groupRouter := Router.Group("websites/groups")
|
||||||
|
groupRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
|
||||||
|
|
||||||
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
|
{
|
||||||
|
groupRouter.GET("", baseApi.GetGroups)
|
||||||
|
}
|
||||||
|
}
|
@ -48,3 +48,19 @@ func (b *Block) AddDirectives(directive Directive) {
|
|||||||
directives := append(b.GetDirectives(), &directive)
|
directives := append(b.GetDirectives(), &directive)
|
||||||
b.Directives = directives
|
b.Directives = directives
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Block) RemoveDirectives(names []string) {
|
||||||
|
nameMaps := make(map[string]struct{}, len(names))
|
||||||
|
for _, name := range names {
|
||||||
|
nameMaps[name] = struct{}{}
|
||||||
|
}
|
||||||
|
directives := b.GetDirectives()
|
||||||
|
var newDirectives []IDirective
|
||||||
|
for _, dir := range directives {
|
||||||
|
if _, ok := nameMaps[dir.GetName()]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newDirectives = append(newDirectives, dir)
|
||||||
|
}
|
||||||
|
b.Directives = newDirectives
|
||||||
|
}
|
||||||
|
@ -88,6 +88,22 @@ func (h *Http) AddDirectives(directive Directive) {
|
|||||||
h.Directives = directives
|
h.Directives = directives
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Http) RemoveDirectives(names []string) {
|
||||||
|
nameMaps := make(map[string]struct{}, len(names))
|
||||||
|
for _, name := range names {
|
||||||
|
nameMaps[name] = struct{}{}
|
||||||
|
}
|
||||||
|
directives := h.GetDirectives()
|
||||||
|
var newDirectives []IDirective
|
||||||
|
for _, dir := range directives {
|
||||||
|
if _, ok := nameMaps[dir.GetName()]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newDirectives = append(newDirectives, dir)
|
||||||
|
}
|
||||||
|
h.Directives = newDirectives
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Http) GetBlock() IBlock {
|
func (h *Http) GetBlock() IBlock {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,11 @@ func NewServer(directive IDirective) (*Server, error) {
|
|||||||
server.Comment = block.GetComment()
|
server.Comment = block.GetComment()
|
||||||
directives := block.GetDirectives()
|
directives := block.GetDirectives()
|
||||||
for _, dir := range directives {
|
for _, dir := range directives {
|
||||||
if dir.GetName() == "listen" {
|
|
||||||
|
switch dir.GetName() {
|
||||||
|
case "listen":
|
||||||
server.Listens = append(server.Listens, NewServerListen(dir.GetParameters()))
|
server.Listens = append(server.Listens, NewServerListen(dir.GetParameters()))
|
||||||
} else {
|
default:
|
||||||
server.Directives = append(server.Directives, dir)
|
server.Directives = append(server.Directives, dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,6 +65,56 @@ func (s *Server) AddListen(bind string, defaultServer bool, params ...string) {
|
|||||||
s.Listens = append(s.Listens, listen)
|
s.Listens = append(s.Listens, listen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) UpdateListen(bind string, defaultServer bool, params ...string) {
|
||||||
|
listen := &ServerListen{
|
||||||
|
Bind: bind,
|
||||||
|
Parameters: params,
|
||||||
|
}
|
||||||
|
if defaultServer {
|
||||||
|
listen.DefaultServer = DefaultServer
|
||||||
|
}
|
||||||
|
var newListens []*ServerListen
|
||||||
|
for _, li := range s.Listens {
|
||||||
|
if li.Bind == bind {
|
||||||
|
newListens = append(newListens, listen)
|
||||||
|
} else {
|
||||||
|
newListens = append(newListens, li)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Listens = newListens
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) UpdateServerName(names []string) {
|
||||||
|
serverNameDirective := Directive{
|
||||||
|
Name: "server_name",
|
||||||
|
Parameters: names,
|
||||||
|
}
|
||||||
|
s.UpdateDirectives("server_name", serverNameDirective)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) UpdateRootProxy(proxy []string) {
|
||||||
|
//TODD 根据ID修改
|
||||||
|
dirs := s.FindDirectives("location")
|
||||||
|
for _, dir := range dirs {
|
||||||
|
location, ok := dir.(*Location)
|
||||||
|
if ok && location.Match == "/" {
|
||||||
|
newDir := Directive{
|
||||||
|
Name: "location",
|
||||||
|
Parameters: []string{"/"},
|
||||||
|
Block: &Block{},
|
||||||
|
}
|
||||||
|
block := &Block{}
|
||||||
|
block.Directives = append(block.Directives, &Directive{
|
||||||
|
Name: "proxy_pass",
|
||||||
|
Parameters: proxy,
|
||||||
|
})
|
||||||
|
newDir.Block = block
|
||||||
|
s.UpdateDirectives("location", newDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) RemoveListenByBind(bind string) {
|
func (s *Server) RemoveListenByBind(bind string) {
|
||||||
index := 0
|
index := 0
|
||||||
listens := s.Listens
|
listens := s.Listens
|
||||||
@ -105,3 +157,19 @@ func (s *Server) AddDirectives(directive Directive) {
|
|||||||
directives := append(s.Directives, &directive)
|
directives := append(s.Directives, &directive)
|
||||||
s.Directives = directives
|
s.Directives = directives
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) RemoveDirectives(names []string) {
|
||||||
|
nameMaps := make(map[string]struct{}, len(names))
|
||||||
|
for _, name := range names {
|
||||||
|
nameMaps[name] = struct{}{}
|
||||||
|
}
|
||||||
|
directives := s.GetDirectives()
|
||||||
|
var newDirectives []IDirective
|
||||||
|
for _, dir := range directives {
|
||||||
|
if _, ok := nameMaps[dir.GetName()]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newDirectives = append(newDirectives, dir)
|
||||||
|
}
|
||||||
|
s.Directives = newDirectives
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ type IBlock interface {
|
|||||||
FindDirectives(directiveName string) []IDirective
|
FindDirectives(directiveName string) []IDirective
|
||||||
UpdateDirectives(directiveName string, directive Directive)
|
UpdateDirectives(directiveName string, directive Directive)
|
||||||
AddDirectives(directive Directive)
|
AddDirectives(directive Directive)
|
||||||
|
RemoveDirectives(names []string)
|
||||||
GetComment() string
|
GetComment() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,3 +92,19 @@ func (us *Upstream) AddDirectives(directive Directive) {
|
|||||||
directives := append(us.GetDirectives(), &directive)
|
directives := append(us.GetDirectives(), &directive)
|
||||||
us.Directives = directives
|
us.Directives = directives
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (us *Upstream) RemoveDirectives(names []string) {
|
||||||
|
nameMaps := make(map[string]struct{}, len(names))
|
||||||
|
for _, name := range names {
|
||||||
|
nameMaps[name] = struct{}{}
|
||||||
|
}
|
||||||
|
directives := us.GetDirectives()
|
||||||
|
var newDirectives []IDirective
|
||||||
|
for _, dir := range directives {
|
||||||
|
if _, ok := nameMaps[dir.GetName()]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newDirectives = append(newDirectives, dir)
|
||||||
|
}
|
||||||
|
us.Directives = newDirectives
|
||||||
|
}
|
||||||
|
@ -5,8 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
components "github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
components "github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -123,10 +121,5 @@ func DumpConfig(c *components.Config, style *Style) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WriteConfig(c *components.Config, style *Style) error {
|
func WriteConfig(c *components.Config, style *Style) error {
|
||||||
dir, _ := filepath.Split(c.FilePath)
|
|
||||||
err := os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return ioutil.WriteFile(c.FilePath, []byte(DumpConfig(c, style)), 0644)
|
return ioutil.WriteFile(c.FilePath, []byte(DumpConfig(c, style)), 0644)
|
||||||
}
|
}
|
||||||
|
4
cmd/server/nginx_conf/gzip.conf
Normal file
4
cmd/server/nginx_conf/gzip.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
gzip on;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_min_length 1k;
|
||||||
|
gzip_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
|
3
cmd/server/nginx_conf/http2https.conf
Normal file
3
cmd/server/nginx_conf/http2https.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
if ($server_port !~ 443){
|
||||||
|
rewrite ^(/.*)$ https://$host$1 permanent;
|
||||||
|
}
|
3
cmd/server/nginx_conf/limit.conf
Normal file
3
cmd/server/nginx_conf/limit.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
limit_conn perserver 300;
|
||||||
|
limit_conn perip 25;
|
||||||
|
limit_rate 512k;
|
14
cmd/server/nginx_conf/nginx_conf.go
Normal file
14
cmd/server/nginx_conf/nginx_conf.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package nginx_conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed ssl.conf
|
||||||
|
var SSL []byte
|
||||||
|
|
||||||
|
//go:embed http2https.conf
|
||||||
|
var HTTPS []byte
|
||||||
|
|
||||||
|
//go:embed website_default.conf
|
||||||
|
var WebsiteDefault []byte
|
9
cmd/server/nginx_conf/ssl.conf
Normal file
9
cmd/server/nginx_conf/ssl.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
ssl_certificate /www/server/panel/vhost/cert/1panel.cloud/fullchain.pem;
|
||||||
|
ssl_certificate_key /www/server/panel/vhost/cert/1panel.cloud/privkey.pem;
|
||||||
|
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 10m;
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000";
|
||||||
|
error_page 497 https://$host$request_uri;
|
17
cmd/server/nginx_conf/website_default.conf
Normal file
17
cmd/server/nginx_conf/website_default.conf
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name ko.wp-1.com;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Host $server_name;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
}
|
||||||
|
access_log /var/log/nginx/nginx-log.log;
|
||||||
|
}
|
@ -88,6 +88,10 @@ export namespace App {
|
|||||||
detailId?: number;
|
detailId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AppInstalledSearch {
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AppService {
|
export interface AppService {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
19
frontend/src/api/interface/website.ts
Normal file
19
frontend/src/api/interface/website.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { CommonModel } from '.';
|
||||||
|
|
||||||
|
export namespace WebSite {
|
||||||
|
export interface WebSiteCreateReq {
|
||||||
|
primaryDomain: string;
|
||||||
|
type: string;
|
||||||
|
alias: string;
|
||||||
|
remark: string;
|
||||||
|
domains: string[];
|
||||||
|
appType: string;
|
||||||
|
appInstallID: number;
|
||||||
|
webSiteGroupID: number;
|
||||||
|
otherDomains: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Group extends CommonModel {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,10 @@ export const GetAppInstalled = (info: ReqPage) => {
|
|||||||
return http.post<ResPage<App.AppInstalled>>('apps/installed', info);
|
return http.post<ResPage<App.AppInstalled>>('apps/installed', info);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SearchAppInstalled = (search: App.AppInstalledSearch) => {
|
||||||
|
return http.post<App.AppInstalled[]>('apps/installed', search);
|
||||||
|
};
|
||||||
|
|
||||||
export const InstalledOp = (op: App.AppInstalledOp) => {
|
export const InstalledOp = (op: App.AppInstalledOp) => {
|
||||||
return http.post<any>('apps/installed/op', op);
|
return http.post<any>('apps/installed/op', op);
|
||||||
};
|
};
|
||||||
|
10
frontend/src/api/modules/website.ts
Normal file
10
frontend/src/api/modules/website.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import http from '@/api';
|
||||||
|
import { WebSite } from '../interface/website';
|
||||||
|
|
||||||
|
export const listGroups = () => {
|
||||||
|
return http.get<WebSite.Group[]>(`/websites/groups`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => {
|
||||||
|
return http.post<any>(`/websites`, req);
|
||||||
|
};
|
@ -662,4 +662,19 @@ export default {
|
|||||||
update: '更新',
|
update: '更新',
|
||||||
versioneSelect: '请选择版本',
|
versioneSelect: '请选择版本',
|
||||||
},
|
},
|
||||||
|
website: {
|
||||||
|
primaryDomain: '主域名',
|
||||||
|
otherDomains: '其他域名',
|
||||||
|
type: '类型',
|
||||||
|
static: '静态网站',
|
||||||
|
deployment: '一键部署',
|
||||||
|
proxy: '反向代理',
|
||||||
|
alias: '代号',
|
||||||
|
remark: '备注',
|
||||||
|
group: '分组',
|
||||||
|
app: '应用',
|
||||||
|
app_new: '新装应用',
|
||||||
|
app_installed: '已装应用',
|
||||||
|
create: '创建网站',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,15 @@ const webSiteRouter = {
|
|||||||
title: 'menu.project',
|
title: 'menu.project',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/websites/projects/config',
|
||||||
|
name: 'WebsiteConfig',
|
||||||
|
component: () => import('@/views/website/project/config/index.vue'),
|
||||||
|
hidden: true,
|
||||||
|
meta: {
|
||||||
|
activeMenu: '/websites',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/websites/config',
|
path: '/websites/config',
|
||||||
name: 'Config',
|
name: 'Config',
|
||||||
|
@ -9,7 +9,7 @@ export const GlobalStore = defineStore({
|
|||||||
state: (): GlobalState => ({
|
state: (): GlobalState => ({
|
||||||
isLogin: false,
|
isLogin: false,
|
||||||
csrfToken: '',
|
csrfToken: '',
|
||||||
assemblySize: 'small',
|
assemblySize: 'default',
|
||||||
language: '',
|
language: '',
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
panelName: '',
|
panelName: '',
|
||||||
|
37
frontend/src/views/website/project/config/index.vue
Normal file
37
frontend/src/views/website/project/config/index.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<LayoutContent :header="'网站设置'" :back-name="'Website'">
|
||||||
|
<el-tabs type="card">
|
||||||
|
<el-tab-pane label="基本">
|
||||||
|
<el-tabs tab-position="left" type="border-card">
|
||||||
|
<el-tab-pane label="域名设置">
|
||||||
|
<ComplexTable>
|
||||||
|
<template #toolbar>
|
||||||
|
<el-button type="primary" plain>{{ '新增域名' }}</el-button>
|
||||||
|
</template>
|
||||||
|
<el-table-column :label="'域名'" prop="backup"></el-table-column>
|
||||||
|
<el-table-column :label="'端口'" prop="remark"></el-table-column>
|
||||||
|
</ComplexTable>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="目录设置">Config</el-tab-pane>
|
||||||
|
<el-tab-pane label="HTTPS">Role</el-tab-pane>
|
||||||
|
<el-tab-pane label="域名跳转">Task</el-tab-pane>
|
||||||
|
<el-tab-pane label="错误页面">Task</el-tab-pane>
|
||||||
|
<el-tab-pane label="过期时间">Task</el-tab-pane>
|
||||||
|
<el-tab-pane label="流量限制">Task</el-tab-pane>
|
||||||
|
<el-tab-pane label="默认文档">Task</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="优化">优化</el-tab-pane>
|
||||||
|
<el-tab-pane label="反代">反代</el-tab-pane>
|
||||||
|
<el-tab-pane label="安全">反代</el-tab-pane>
|
||||||
|
<el-tab-pane label="备份">反代</el-tab-pane>
|
||||||
|
<el-tab-pane label="日志">反代</el-tab-pane>
|
||||||
|
<el-tab-pane label="源文">反代</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</LayoutContent>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
</script>
|
135
frontend/src/views/website/project/create/index.vue
Normal file
135
frontend/src/views/website/project/create/index.vue
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="open" :title="$t('website.create')" width="40%" :before-close="handleClose">
|
||||||
|
<el-form ref="websiteForm" label-position="right" :model="website" label-width="100px" :rules="rules">
|
||||||
|
<el-form-item :label="$t('website.type')" prop="type">
|
||||||
|
<el-select v-model="website.type">
|
||||||
|
<el-option :label="$t('website.deployment')" value="deployment"></el-option>
|
||||||
|
<el-option :label="$t('website.static')" value="static"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.group')" prop="webSiteGroupID">
|
||||||
|
<el-select v-model="website.webSiteGroupID">
|
||||||
|
<el-option
|
||||||
|
v-for="(group, index) in groups"
|
||||||
|
:key="index"
|
||||||
|
:label="group.name"
|
||||||
|
:value="group.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<div v-if="website.type === 'deployment'">
|
||||||
|
<el-form-item prop="appType">
|
||||||
|
<el-radio-group v-model="website.appType">
|
||||||
|
<el-radio :label="'installed'" :value="'installed'">
|
||||||
|
{{ $t('website.app_installed') }}
|
||||||
|
</el-radio>
|
||||||
|
<el-radio :label="'new'">
|
||||||
|
{{ $t('website.app_new') }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="website.appType == 'installed'"
|
||||||
|
:label="$t('website.app_installed')"
|
||||||
|
prop="appInstallID"
|
||||||
|
>
|
||||||
|
<el-select v-model="website.appInstallID">
|
||||||
|
<el-option
|
||||||
|
v-for="(appInstall, index) in appInstalles"
|
||||||
|
:key="index"
|
||||||
|
:label="appInstall.name"
|
||||||
|
:value="appInstall.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
|
||||||
|
<el-input v-model="website.primaryDomain"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.otherDomains')" prop="otherDomains">
|
||||||
|
<el-input v-model="website.otherDomains"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.alias')" prop="alias">
|
||||||
|
<el-input v-model="website.alias"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.remark')" prop="remark">
|
||||||
|
<el-input v-model="website.remark"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="submit(websiteForm)" :disabled="loading">
|
||||||
|
{{ $t('commons.button.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="CreateWebSite">
|
||||||
|
import { App } from '@/api/interface/app';
|
||||||
|
import { WebSite } from '@/api/interface/website';
|
||||||
|
import { SearchAppInstalled } from '@/api/modules/app';
|
||||||
|
import { CreateWebsite, listGroups } from '@/api/modules/website';
|
||||||
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import { FormRules, ElDialog, ElForm, FormInstance } from 'element-plus';
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
const websiteForm = ref<FormInstance>();
|
||||||
|
const website = reactive({
|
||||||
|
primaryDomain: '',
|
||||||
|
type: 'deployment',
|
||||||
|
alias: '',
|
||||||
|
remark: '',
|
||||||
|
domains: [],
|
||||||
|
appType: 'installed',
|
||||||
|
appInstallID: 0,
|
||||||
|
webSiteGroupID: 1,
|
||||||
|
otherDomains: '',
|
||||||
|
});
|
||||||
|
let rules = reactive<FormRules>({
|
||||||
|
primaryDomain: [Rules.requiredInput],
|
||||||
|
alias: [Rules.requiredInput],
|
||||||
|
type: [Rules.requiredInput],
|
||||||
|
webSiteGroupID: [Rules.requiredInput],
|
||||||
|
appInstallID: [Rules.requiredInput],
|
||||||
|
appType: [Rules.requiredInput],
|
||||||
|
});
|
||||||
|
|
||||||
|
let open = ref(false);
|
||||||
|
let loading = ref(false);
|
||||||
|
let groups = ref<WebSite.Group[]>([]);
|
||||||
|
let appInstalles = ref<App.AppInstalled[]>([]);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
open.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const acceptParams = async () => {
|
||||||
|
await listGroups().then((res) => {
|
||||||
|
groups.value = res.data;
|
||||||
|
open.value = true;
|
||||||
|
});
|
||||||
|
await SearchAppInstalled({ type: 'website' }).then((res) => {
|
||||||
|
appInstalles.value = res.data;
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
website.appInstallID = res.data[0].id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CreateWebsite(website).then(() => {});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
acceptParams,
|
||||||
|
});
|
||||||
|
</script>
|
@ -1,7 +1,69 @@
|
|||||||
<template>
|
<template>
|
||||||
<LayoutContent></LayoutContent>
|
<LayoutContent :header="'网站'">
|
||||||
|
<ComplexTable :data="data" @search="search()">
|
||||||
|
<template #toolbar>
|
||||||
|
<el-button type="primary" plain @click="openCreate">{{ '新建网站' }}</el-button>
|
||||||
|
<el-button type="primary" plain>{{ '修改默认页' }}</el-button>
|
||||||
|
<el-button type="primary" plain>{{ '默认站点' }}</el-button>
|
||||||
|
</template>
|
||||||
|
<el-table-column :label="$t('commons.table.name')" fix show-overflow-tooltip prop="primaryDomain">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-link @click="openConfig">{{ row.primaryDomain }}</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('commons.table.status')" prop="status"></el-table-column>
|
||||||
|
<el-table-column :label="'备份'" prop="backup"></el-table-column>
|
||||||
|
<el-table-column :label="'备注'" prop="remark"></el-table-column>
|
||||||
|
<el-table-column :label="'SSL证书'" prop="ssl"></el-table-column>
|
||||||
|
<fu-table-operations
|
||||||
|
:ellipsis="1"
|
||||||
|
:buttons="buttons"
|
||||||
|
:label="$t('commons.table.operate')"
|
||||||
|
fixed="right"
|
||||||
|
fix
|
||||||
|
/>
|
||||||
|
</ComplexTable>
|
||||||
|
<CreateWebSite ref="createRef"></CreateWebSite>
|
||||||
|
</LayoutContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import { onMounted, ref } from '@vue/runtime-core';
|
||||||
|
import router from '@/routers';
|
||||||
|
import CreateWebSite from './create/index.vue';
|
||||||
|
|
||||||
|
const createRef = ref();
|
||||||
|
|
||||||
|
const data = ref();
|
||||||
|
const search = async () => {
|
||||||
|
data.value = [
|
||||||
|
{
|
||||||
|
primaryDomain: 'www.baicu.com',
|
||||||
|
status: 'Running',
|
||||||
|
backup: '1',
|
||||||
|
remark: '主网站',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const openConfig = () => {
|
||||||
|
router.push({ name: 'WebsiteConfig' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttons = [
|
||||||
|
{
|
||||||
|
label: '设置',
|
||||||
|
click: open,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const openCreate = () => {
|
||||||
|
createRef.value.acceptParams();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
search();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user