diff --git a/app/console/commands/panel.go b/app/console/commands/panel.go index 689e4e82..35ce8ad6 100644 --- a/app/console/commands/panel.go +++ b/app/console/commands/panel.go @@ -15,6 +15,7 @@ import ( "github.com/goravel/framework/support/color" "github.com/spf13/cast" + requests "github.com/TheTNB/panel/app/http/requests/website" "github.com/TheTNB/panel/app/models" "github.com/TheTNB/panel/internal/services" "github.com/TheTNB/panel/pkg/io" @@ -649,7 +650,7 @@ func (receiver *Panel) Handle(ctx console.Context) error { return nil } - if err = website.Delete(id); err != nil { + if err = website.Delete(requests.Delete{ID: id}); err != nil { color.Red().Printfln(err.Error()) return nil } diff --git a/app/http/controllers/website_controller.go b/app/http/controllers/website_controller.go index e876bba6..aac2ae25 100644 --- a/app/http/controllers/website_controller.go +++ b/app/http/controllers/website_controller.go @@ -118,23 +118,22 @@ func (r *WebsiteController) Add(ctx http.Context) http.Response { // @Accept json // @Produce json // @Security BearerToken -// @Param id path int true "网站 ID" -// @Success 200 {object} SuccessResponse -// @Router /panel/websites/{id} [delete] +// @Param data body requests.Delete true "request" +// @Success 200 {object} SuccessResponse +// @Router /panel/websites/delete [post] func (r *WebsiteController) Delete(ctx http.Context) http.Response { - var idRequest requests.ID - sanitize := SanitizeRequest(ctx, &idRequest) + var deleteRequest requests.Delete + sanitize := SanitizeRequest(ctx, &deleteRequest) if sanitize != nil { return sanitize } - err := r.website.Delete(idRequest.ID) - if err != nil { + if err := r.website.Delete(deleteRequest); err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ - "id": idRequest.ID, + "id": deleteRequest.ID, "error": err.Error(), }).Info("删除网站失败") - return Error(ctx, http.StatusInternalServerError, "删除网站失败: "+err.Error()) + return Error(ctx, http.StatusInternalServerError, err.Error()) } return Success(ctx, nil) diff --git a/app/http/requests/website/delete.go b/app/http/requests/website/delete.go new file mode 100644 index 00000000..a43a583b --- /dev/null +++ b/app/http/requests/website/delete.go @@ -0,0 +1,40 @@ +package requests + +import ( + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/contracts/validation" +) + +type Delete struct { + ID uint `form:"id" json:"id" filter:"uint"` + Path bool `form:"path" json:"path"` + DB bool `form:"db" json:"db"` +} + +func (r *Delete) Authorize(ctx http.Context) error { + return nil +} + +func (r *Delete) Rules(ctx http.Context) map[string]string { + return map[string]string{ + "id": "required|exists:websites,id", + "path": "bool", + "db": "bool", + } +} + +func (r *Delete) Filters(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *Delete) Messages(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *Delete) Attributes(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *Delete) PrepareForValidation(ctx http.Context, data validation.Data) error { + return nil +} diff --git a/docs/docs.go b/docs/docs.go index 166d91ac..eac911c4 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -3574,8 +3574,8 @@ const docTemplate = `{ } } }, - "/panel/websites/{id}": { - "delete": { + "/panel/websites/delete": { + "post": { "security": [ { "BearerToken": [] @@ -3593,11 +3593,13 @@ const docTemplate = `{ "summary": "删除网站", "parameters": [ { - "type": "integer", - "description": "网站 ID", - "name": "id", - "in": "path", - "required": true + "description": "request", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.Delete" + } } ], "responses": { @@ -5506,6 +5508,20 @@ const docTemplate = `{ } } }, + "requests.Delete": { + "type": "object", + "properties": { + "db": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "path": { + "type": "boolean" + } + } + }, "requests.DeleteBackup": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index c1da1cbe..fded4687 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -3567,8 +3567,8 @@ } } }, - "/panel/websites/{id}": { - "delete": { + "/panel/websites/delete": { + "post": { "security": [ { "BearerToken": [] @@ -3586,11 +3586,13 @@ "summary": "删除网站", "parameters": [ { - "type": "integer", - "description": "网站 ID", - "name": "id", - "in": "path", - "required": true + "description": "request", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.Delete" + } } ], "responses": { @@ -5499,6 +5501,20 @@ } } }, + "requests.Delete": { + "type": "object", + "properties": { + "db": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "path": { + "type": "boolean" + } + } + }, "requests.DeleteBackup": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 1810d2ba..16e1a66c 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -377,6 +377,15 @@ definitions: type: type: string type: object + requests.Delete: + properties: + db: + type: boolean + id: + type: integer + path: + type: boolean + type: object requests.DeleteBackup: properties: name: @@ -2840,28 +2849,6 @@ paths: summary: 添加网站 tags: - 网站 - /panel/websites/{id}: - delete: - consumes: - - application/json - parameters: - - description: 网站 ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/controllers.SuccessResponse' - security: - - BearerToken: [] - summary: 删除网站 - tags: - - 网站 /panel/websites/{id}/config: get: consumes: @@ -3048,6 +3035,29 @@ paths: summary: 更新网站备注 tags: - 网站 + /panel/websites/delete: + post: + consumes: + - application/json + parameters: + - description: request + in: body + name: data + required: true + schema: + $ref: '#/definitions/requests.Delete' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + security: + - BearerToken: [] + summary: 删除网站 + tags: + - 网站 /plugins/frp/config: get: description: 获取 Frp 配置 diff --git a/internal/services/website.go b/internal/services/website.go index 2922ee11..8e3aeae2 100644 --- a/internal/services/website.go +++ b/internal/services/website.go @@ -17,6 +17,7 @@ import ( "github.com/TheTNB/panel/app/models" "github.com/TheTNB/panel/internal" "github.com/TheTNB/panel/pkg/cert" + "github.com/TheTNB/panel/pkg/db" "github.com/TheTNB/panel/pkg/io" "github.com/TheTNB/panel/pkg/shell" "github.com/TheTNB/panel/pkg/str" @@ -296,16 +297,25 @@ server rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) if website.Db && website.DbType == "mysql" { - _, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE DATABASE IF NOT EXISTS ` + website.DbName + ` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"`) - _, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE USER '` + website.DbUser + `'@'localhost' IDENTIFIED BY '` + website.DbPassword + `';"`) - _, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "GRANT ALL PRIVILEGES ON ` + website.DbName + `.* TO '` + website.DbUser + `'@'localhost';"`) - _, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "FLUSH PRIVILEGES;"`) + mysql, err := db.NewMySQL("root", rootPassword, "/tmp/mysql.sock", "unix") + if err != nil { + return models.Website{}, err + } + if err = mysql.DatabaseCreate(website.DbName); err != nil { + return models.Website{}, err + } + if err = mysql.UserCreate(website.DbUser, website.DbPassword); err != nil { + return models.Website{}, err + } + if err = mysql.PrivilegesGrant(website.DbUser, website.DbName); err != nil { + return models.Website{}, err + } } if website.Db && website.DbType == "postgresql" { - _, _ = shell.Execf(`echo "CREATE DATABASE ` + website.DbName + `;" | su - postgres -c "psql"`) - _, _ = shell.Execf(`echo "CREATE USER ` + website.DbUser + ` WITH PASSWORD '` + website.DbPassword + `';" | su - postgres -c "psql"`) - _, _ = shell.Execf(`echo "ALTER DATABASE ` + website.DbName + ` OWNER TO ` + website.DbUser + `;" | su - postgres -c "psql"`) - _, _ = shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + website.DbName + ` TO ` + website.DbUser + `;" | su - postgres -c "psql"`) + _, _ = shell.Execf(`echo "CREATE DATABASE '%s';" | su - postgres -c "psql"`, website.DbName) + _, _ = shell.Execf(`echo "CREATE USER '%s' WITH PASSWORD '%s';" | su - postgres -c "psql"`, website.DbUser, website.DbPassword) + _, _ = shell.Execf(`echo "ALTER DATABASE '%s' OWNER TO '%s';" | su - postgres -c "psql"`, website.DbName, website.DbUser) + _, _ = shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE '%s' TO '%s';" | su - postgres -c "psql"`, website.DbName, website.DbUser) userConfig := "host " + website.DbName + " " + website.DbUser + " 127.0.0.1/32 scram-sha-256" _, _ = shell.Execf(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`) _ = systemctl.Reload("postgresql") @@ -540,9 +550,9 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error { } // Delete 删除网站 -func (r *WebsiteImpl) Delete(id uint) error { +func (r *WebsiteImpl) Delete(request requests.Delete) error { var website models.Website - if err := facades.Orm().Query().With("Cert").Where("id", id).FirstOrFail(&website); err != nil { + if err := facades.Orm().Query().With("Cert").Where("id", request.ID).FirstOrFail(&website); err != nil { return err } @@ -559,7 +569,21 @@ func (r *WebsiteImpl) Delete(id uint) error { _ = io.Remove("/www/server/vhost/acme/" + website.Name + ".conf") _ = io.Remove("/www/server/vhost/ssl/" + website.Name + ".pem") _ = io.Remove("/www/server/vhost/ssl/" + website.Name + ".key") - _ = io.Remove(website.Path) + + if request.Path { + _ = io.Remove(website.Path) + } + if request.DB { + rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) + mysql, err := db.NewMySQL("root", rootPassword, "/tmp/mysql.sock", "unix") + if err != nil { + return err + } + _ = mysql.DatabaseDrop(website.Name) + _ = mysql.UserDrop(website.Name) + _, _ = shell.Execf(`echo "DROP DATABASE IF EXISTS '%s';" | su - postgres -c "psql"`, website.Name) + _, _ = shell.Execf(`echo "DROP USER IF EXISTS '%s';" | su - postgres -c "psql"`, website.Name) + } err := systemctl.Reload("openresty") if err != nil { diff --git a/internal/website.go b/internal/website.go index 587a78f9..f6af4499 100644 --- a/internal/website.go +++ b/internal/website.go @@ -10,7 +10,7 @@ type Website interface { List(page int, limit int) (int64, []models.Website, error) Add(website types.WebsiteAdd) (models.Website, error) SaveConfig(config requests.SaveConfig) error - Delete(id uint) error + Delete(id requests.Delete) error GetConfig(id uint) (types.WebsiteSetting, error) GetConfigByName(name string) (types.WebsiteSetting, error) GetIDByName(name string) (uint, error) diff --git a/pkg/shell/exec.go b/pkg/shell/exec.go index f91e2c28..e4bc32e6 100644 --- a/pkg/shell/exec.go +++ b/pkg/shell/exec.go @@ -17,7 +17,7 @@ import ( // Execf 执行 shell 命令 func Execf(shell string, args ...any) (string, error) { if !CheckArgs(slice.ToString(args)...) { - return "", errors.New("你想干什么?") + return "", errors.New("发现危险的命令参数,中止执行") } var cmd *exec.Cmd @@ -39,7 +39,7 @@ func Execf(shell string, args ...any) (string, error) { // ExecfAsync 异步执行 shell 命令 func ExecfAsync(shell string, args ...any) error { if !CheckArgs(slice.ToString(args)...) { - return errors.New("你想干什么?") + return errors.New("发现危险的命令参数,中止执行") } var cmd *exec.Cmd @@ -67,7 +67,7 @@ func ExecfAsync(shell string, args ...any) error { // ExecfWithTimeout 执行 shell 命令并设置超时时间 func ExecfWithTimeout(timeout time.Duration, shell string, args ...any) (string, error) { if !CheckArgs(slice.ToString(args)...) { - return "", errors.New("你想干什么?") + return "", errors.New("发现危险的命令参数,中止执行") } var cmd *exec.Cmd diff --git a/routes/api.go b/routes/api.go index cd1370d3..8376f912 100644 --- a/routes/api.go +++ b/routes/api.go @@ -48,7 +48,7 @@ func Api() { websiteController := controllers.NewWebsiteController() r.Get("/", websiteController.List) r.Post("/", websiteController.Add) - r.Delete("{id}", websiteController.Delete) + r.Post("delete", websiteController.Delete) r.Get("{id}/config", websiteController.GetConfig) r.Post("{id}/config", websiteController.SaveConfig) r.Delete("{id}/log", websiteController.ClearLog)