mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 06:47:20 +08:00
feat: 完善验证器
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/go-playground/validator/v10/translations/zh"
|
||||
|
||||
"github.com/TheTNB/panel/internal/app"
|
||||
"github.com/TheTNB/panel/internal/http/rule"
|
||||
)
|
||||
|
||||
func initValidator() {
|
||||
@@ -23,4 +24,7 @@ func initValidator() {
|
||||
|
||||
app.Translator = &trans
|
||||
app.Validator = validate
|
||||
if err := rule.RegisterRules(validate); err != nil {
|
||||
log.Fatalf("failed to register validator rules: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-rat/utils/hash"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"github.com/go-rat/utils/hash"
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/gookit/color"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package request
|
||||
|
||||
type App struct {
|
||||
Slug string `json:"slug" form:"slug" validate:"required"`
|
||||
Slug string `json:"slug" form:"slug" validate:"required,not_exists=apps slug"`
|
||||
Channel string `json:"channel" form:"channel" validate:"required"`
|
||||
}
|
||||
|
||||
type AppSlug struct {
|
||||
Slug string `json:"slug" form:"slug" validate:"required"`
|
||||
Slug string `json:"slug" form:"slug" validate:"required,exists=apps slug"`
|
||||
}
|
||||
|
||||
type AppUpdateShow struct {
|
||||
Slug string `json:"slug" form:"slug" validate:"required"`
|
||||
Show bool `json:"show" form:"show" validate:"required"`
|
||||
Slug string `json:"slug" form:"slug" validate:"required,exists=apps slug"`
|
||||
Show bool `json:"show" form:"show"`
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ type CertCreate struct {
|
||||
}
|
||||
|
||||
type CertUpdate struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=certs id"`
|
||||
Type string `form:"type" json:"type" validate:"required"`
|
||||
Domains []string `form:"domains" json:"domains" validate:"min=1,dive,required"`
|
||||
AutoRenew bool `form:"auto_renew" json:"auto_renew"`
|
||||
@@ -20,6 +20,6 @@ type CertUpdate struct {
|
||||
}
|
||||
|
||||
type CertDeploy struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=certs id"`
|
||||
WebsiteID uint `form:"website_id" json:"website_id" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ type CertAccountCreate struct {
|
||||
}
|
||||
|
||||
type CertAccountUpdate struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=cert_accounts id"`
|
||||
CA string `form:"ca" json:"ca" validate:"required"`
|
||||
Email string `form:"email" json:"email" validate:"required"`
|
||||
Kid string `form:"kid" json:"kid"`
|
||||
|
||||
@@ -9,7 +9,7 @@ type CertDNSCreate struct {
|
||||
}
|
||||
|
||||
type CertDNSUpdate struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=cert_dns id"`
|
||||
Type string `form:"type" json:"type" validate:"required"`
|
||||
Name string `form:"name" json:"name" validate:"required"`
|
||||
Data acme.DNSParam `form:"data" json:"data"`
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package request
|
||||
|
||||
type CronCreate struct {
|
||||
Name string `form:"name" json:"name" validate:"required"`
|
||||
Name string `form:"name" json:"name" validate:"required,not_exists=crons name"`
|
||||
Type string `form:"type" json:"type" validate:"required"`
|
||||
Time string `form:"time" json:"time" validate:"required"`
|
||||
Time string `form:"time" json:"time" validate:"required,cron"`
|
||||
Script string `form:"script" json:"script"`
|
||||
BackupType string `form:"backup_type" json:"backup_type" validate:"required"`
|
||||
BackupPath string `form:"backup_path" json:"backup_path"`
|
||||
@@ -12,13 +12,13 @@ type CronCreate struct {
|
||||
}
|
||||
|
||||
type CronUpdate struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=crons id"`
|
||||
Name string `form:"name" json:"name" validate:"required"`
|
||||
Time string `form:"time" json:"time" validate:"required"`
|
||||
Time string `form:"time" json:"time" validate:"required,cron"`
|
||||
Script string `form:"script" json:"script" validate:"required"`
|
||||
}
|
||||
|
||||
type CronStatus struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=crons id"`
|
||||
Status bool `form:"status" json:"status"`
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ type WebsiteDefaultConfig struct {
|
||||
}
|
||||
|
||||
type WebsiteCreate struct {
|
||||
Name string `form:"name" json:"name" validate:"required"`
|
||||
Name string `form:"name" json:"name" validate:"required,not_exists=websites name"`
|
||||
Listens []string `form:"listens" json:"listens" validate:"min=1,dive,required"`
|
||||
Domains []string `form:"domains" json:"domains" validate:"min=1,dive,required"`
|
||||
Path string `form:"path" json:"path"`
|
||||
@@ -21,13 +21,13 @@ type WebsiteCreate struct {
|
||||
}
|
||||
|
||||
type WebsiteDelete struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=websites id"`
|
||||
Path bool `form:"path" json:"path"`
|
||||
DB bool `form:"db" json:"db"`
|
||||
}
|
||||
|
||||
type WebsiteUpdate struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=websites id"`
|
||||
Listens []types.WebsiteListen `form:"listens" json:"listens" validate:"min=1"`
|
||||
Domains []string `form:"domains" json:"domains" validate:"min=1,dive,required"`
|
||||
HTTPS bool `form:"https" json:"https"`
|
||||
@@ -46,11 +46,11 @@ type WebsiteUpdate struct {
|
||||
}
|
||||
|
||||
type WebsiteUpdateRemark struct {
|
||||
ID uint `form:"id" json:"id" validate:"required"`
|
||||
ID uint `form:"id" json:"id" validate:"required,exists=websites id"`
|
||||
Remark string `form:"remark" json:"remark"`
|
||||
}
|
||||
|
||||
type WebsiteUpdateStatus struct {
|
||||
ID uint `json:"id" form:"id" validate:"required"`
|
||||
ID uint `json:"id" form:"id" validate:"required,exists=websites id"`
|
||||
Status bool `json:"status" form:"status"`
|
||||
}
|
||||
|
||||
42
internal/http/rule/exists.go
Normal file
42
internal/http/rule/exists.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Exists struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
func NewExists(db *gorm.DB) *Exists {
|
||||
return &Exists{DB: db}
|
||||
}
|
||||
|
||||
// Exists 格式 `exists=categories,id,other_field`
|
||||
func (r *Exists) Exists(fl validator.FieldLevel) bool {
|
||||
requestValue := fl.Field().Interface()
|
||||
params := strings.Fields(fl.Param())
|
||||
if len(params) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
tableName := params[0]
|
||||
fieldNames := params[1:]
|
||||
|
||||
query := r.DB.Table(tableName).Where(fmt.Sprintf("%s = ?", fieldNames[0]), requestValue)
|
||||
for _, fieldName := range fieldNames[1:] {
|
||||
query = query.Or(fmt.Sprintf("%s = ?", fieldName), requestValue)
|
||||
}
|
||||
|
||||
var count int64
|
||||
err := query.Count(&count).Error
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return count != 0
|
||||
}
|
||||
42
internal/http/rule/not_exists.go
Normal file
42
internal/http/rule/not_exists.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type NotExists struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
func NewNotExists(db *gorm.DB) *NotExists {
|
||||
return &NotExists{DB: db}
|
||||
}
|
||||
|
||||
// NotExists 格式 `not_exists=categories,id,other_field`
|
||||
func (r *NotExists) NotExists(fl validator.FieldLevel) bool {
|
||||
requestValue := fl.Field().Interface()
|
||||
params := strings.Fields(fl.Param())
|
||||
if len(params) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
tableName := params[0]
|
||||
fieldNames := params[1:]
|
||||
|
||||
query := r.DB.Table(tableName).Where(fmt.Sprintf("%s = ?", fieldNames[0]), requestValue)
|
||||
for _, fieldName := range fieldNames[1:] {
|
||||
query = query.Or(fmt.Sprintf("%s = ?", fieldName), requestValue)
|
||||
}
|
||||
|
||||
var count int64
|
||||
err := query.Count(&count).Error
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return count == 0
|
||||
}
|
||||
26
internal/http/rule/regexp.go
Normal file
26
internal/http/rule/regexp.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type Regexp struct{}
|
||||
|
||||
func NewRegexp() *Regexp {
|
||||
return &Regexp{}
|
||||
}
|
||||
|
||||
func (r *Regexp) Regexp(fl validator.FieldLevel) bool {
|
||||
// 从标签中获取正则,格式类似于 `regexp=^[a-zA-Z0-9_]+$`
|
||||
pattern := fl.Param()
|
||||
value := fl.Field().String()
|
||||
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return re.MatchString(value)
|
||||
}
|
||||
53
internal/http/rule/rule.go
Normal file
53
internal/http/rule/rule.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/TheTNB/panel/internal/app"
|
||||
)
|
||||
|
||||
func RegisterRules(v *validator.Validate) error {
|
||||
if err := v.RegisterValidation("exists", NewExists(app.Orm).Exists); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterValidation("not_exists", NewNotExists(app.Orm).NotExists); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterValidation("regexp", NewRegexp().Regexp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.RegisterTranslation("exists", *app.Translator,
|
||||
func(ut ut.Translator) error {
|
||||
return ut.Add("exists", "{0} 不存在", true)
|
||||
},
|
||||
func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("exists", fe.Field())
|
||||
return t
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterTranslation("not_exists", *app.Translator,
|
||||
func(ut ut.Translator) error {
|
||||
return ut.Add("not_exists", "{0} 已存在", true)
|
||||
},
|
||||
func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("not_exists", fe.Field())
|
||||
return t
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterTranslation("regexp", *app.Translator,
|
||||
func(ut ut.Translator) error {
|
||||
return ut.Add("regexp", "{0} 格式不正确", true)
|
||||
},
|
||||
func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("regexp", fe.Field())
|
||||
return t
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func NewCertRenew() *CertRenew {
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver *CertRenew) Run() {
|
||||
func (r *CertRenew) Run() {
|
||||
if types.Status != types.StatusNormal {
|
||||
return
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func (receiver *CertRenew) Run() {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = receiver.certRepo.Renew(cert.ID)
|
||||
_, err = r.certRepo.Renew(cert.ID)
|
||||
if err != nil {
|
||||
app.Logger.Error("续签证书失败", zap.Error(err))
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func NewMonitoring() *Monitoring {
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver *Monitoring) Run() {
|
||||
func (r *Monitoring) Run() {
|
||||
if types.Status != types.StatusNormal {
|
||||
return
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func (receiver *Monitoring) Run() {
|
||||
//task := data.NewTaskRepo()
|
||||
//_ = task.DispatchWaiting()
|
||||
|
||||
monitor, err := receiver.settingRepo.Get(biz.SettingKeyMonitor)
|
||||
monitor, err := r.settingRepo.Get(biz.SettingKeyMonitor)
|
||||
if err != nil || !cast.ToBool(monitor) {
|
||||
return
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func (receiver *Monitoring) Run() {
|
||||
}
|
||||
|
||||
// 删除过期数据
|
||||
dayStr, err := receiver.settingRepo.Get(biz.SettingKeyMonitorDays)
|
||||
dayStr, err := r.settingRepo.Get(biz.SettingKeyMonitorDays)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func NewPanelTask() *PanelTask {
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver *PanelTask) Run() {
|
||||
func (r *PanelTask) Run() {
|
||||
types.Status = types.StatusMaintain
|
||||
|
||||
// 优化数据库
|
||||
@@ -41,21 +41,21 @@ func (receiver *PanelTask) Run() {
|
||||
}
|
||||
|
||||
// 备份面板
|
||||
if err := receiver.backupRepo.Create(biz.BackupTypePanel, ""); err != nil {
|
||||
if err := r.backupRepo.Create(biz.BackupTypePanel, ""); err != nil {
|
||||
app.Logger.Error("备份面板失败", zap.Error(err))
|
||||
}
|
||||
|
||||
// 清理备份
|
||||
path, err := receiver.backupRepo.GetPath("panel")
|
||||
path, err := r.backupRepo.GetPath("panel")
|
||||
if err == nil {
|
||||
if err = receiver.backupRepo.ClearExpired(path, "panel_", 10); err != nil {
|
||||
if err = r.backupRepo.ClearExpired(path, "panel_", 10); err != nil {
|
||||
app.Logger.Error("清理面板备份失败", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 更新商店缓存
|
||||
if offline, err := receiver.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
|
||||
if err = receiver.appRepo.UpdateCache(); err != nil {
|
||||
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
|
||||
if err = r.appRepo.UpdateCache(); err != nil {
|
||||
app.Logger.Error("更新商店缓存失败", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,19 @@ func NewProcessTask(taskRepo biz.TaskRepo) *ProcessTask {
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver *ProcessTask) Handle(args ...any) error {
|
||||
func (r *ProcessTask) Handle(args ...any) error {
|
||||
taskID, ok := args[0].(uint)
|
||||
if !ok {
|
||||
return errors.New("参数错误")
|
||||
}
|
||||
receiver.taskID = taskID
|
||||
r.taskID = taskID
|
||||
|
||||
task, err := receiver.taskRepo.Get(taskID)
|
||||
task, err := r.taskRepo.Get(taskID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = receiver.taskRepo.UpdateStatus(taskID, biz.TaskStatusRunning); err != nil {
|
||||
if err = r.taskRepo.UpdateStatus(taskID, biz.TaskStatusRunning); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -40,13 +40,13 @@ func (receiver *ProcessTask) Handle(args ...any) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = receiver.taskRepo.UpdateStatus(taskID, biz.TaskStatusSuccess); err != nil {
|
||||
if err = r.taskRepo.UpdateStatus(taskID, biz.TaskStatusSuccess); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (receiver *ProcessTask) ErrHandle(err error) {
|
||||
_ = receiver.taskRepo.UpdateStatus(receiver.taskID, biz.TaskStatusFailed)
|
||||
func (r *ProcessTask) ErrHandle(err error) {
|
||||
_ = r.taskRepo.UpdateStatus(r.taskID, biz.TaskStatusFailed)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user