2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 07:57:21 +08:00

feat: 删除网站支持删除数据库

This commit is contained in:
耗子
2024-06-28 02:52:31 +08:00
parent c70758339f
commit 4d76e9286d
10 changed files with 168 additions and 62 deletions

View File

@@ -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
}

View File

@@ -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)

View 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
}

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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 配置

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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

View File

@@ -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)