mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 07:57:21 +08:00
feat: 删除网站支持删除数据库
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
40
app/http/requests/website/delete.go
Normal file
40
app/http/requests/website/delete.go
Normal file
@@ -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
|
||||
}
|
||||
30
docs/docs.go
30
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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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 配置
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user