From 71d9151fa0021bd4513226041e007929e0d980dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Mon, 12 May 2025 22:45:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A02fa=EF=BC=8C=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E8=B6=85=E6=97=B6=EF=BC=8C=E7=BB=91=E5=AE=9A=E5=9F=9F?= =?UTF-8?q?=E5=90=8D=E3=80=81IP=E3=80=81UA=E7=9A=84=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/biz/setting.go | 9 +++ internal/data/setting.go | 132 ++++++++++++++++++++++++++++--- internal/http/request/setting.go | 33 ++++---- internal/service/cli.go | 6 ++ 4 files changed, 153 insertions(+), 27 deletions(-) diff --git a/internal/biz/setting.go b/internal/biz/setting.go index 87a76a85..43651874 100644 --- a/internal/biz/setting.go +++ b/internal/biz/setting.go @@ -19,6 +19,12 @@ const ( SettingKeyMySQLRootPassword SettingKey = "mysql_root_password" SettingKeyOfflineMode SettingKey = "offline_mode" SettingKeyAutoUpdate SettingKey = "auto_update" + SettingKeyTwoFA SettingKey = "two_fa" + SettingKeyTwoFAToken SettingKey = "two_fa_token" + SettingKeyLoginTimeout SettingKey = "login_timeout" + SettingKeyBindDomain SettingKey = "bind_domain" + SettingKeyBindIP SettingKey = "bind_ip" + SettingKeyBindUA SettingKey = "bind_ua" ) type Setting struct { @@ -32,7 +38,10 @@ type Setting struct { type SettingRepo interface { Get(key SettingKey, defaultValue ...string) (string, error) GetBool(key SettingKey, defaultValue ...bool) (bool, error) + GetInt(key SettingKey, defaultValue ...int) (int, error) + GetSlice(key SettingKey, defaultValue ...[]string) ([]string, error) Set(key SettingKey, value string) error + SetSlice(key SettingKey, value []string) error Delete(key SettingKey) error GetPanelSetting(ctx context.Context) (*request.PanelSetting, error) UpdatePanelSetting(ctx context.Context, setting *request.PanelSetting) (bool, error) diff --git a/internal/data/setting.go b/internal/data/setting.go index acf1eb92..9d742a04 100644 --- a/internal/data/setting.go +++ b/internal/data/setting.go @@ -2,6 +2,7 @@ package data import ( "context" + "encoding/json" "errors" "path/filepath" @@ -68,6 +69,48 @@ func (r *settingRepo) GetBool(key biz.SettingKey, defaultValue ...bool) (bool, e return cast.ToBool(setting.Value), nil } +func (r *settingRepo) GetInt(key biz.SettingKey, defaultValue ...int) (int, error) { + setting := new(biz.Setting) + if err := r.db.Where("key = ?", key).First(setting).Error; err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return 0, err + } + } + + if setting.Value == "" && len(defaultValue) > 0 { + return defaultValue[0], nil + } + + return cast.ToInt(setting.Value), nil +} + +func (r *settingRepo) GetSlice(key biz.SettingKey, defaultValue ...[]string) ([]string, error) { + setting := new(biz.Setting) + if err := r.db.Where("key = ?", key).First(setting).Error; err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + } + + // 设置值为空时提前返回 + slice := make([]string, 0) + if setting.Value == "" { + if len(defaultValue) > 0 { + return defaultValue[0], nil + } + return slice, nil + } + + if err := json.Unmarshal([]byte(setting.Value), &slice); err != nil { + return nil, err + } + if len(slice) == 0 && len(defaultValue) > 0 { + return defaultValue[0], nil + } + + return slice, nil +} + func (r *settingRepo) Set(key biz.SettingKey, value string) error { setting := new(biz.Setting) if err := r.db.Where("key = ?", key).First(setting).Error; err != nil { @@ -81,6 +124,28 @@ func (r *settingRepo) Set(key biz.SettingKey, value string) error { return r.db.Save(setting).Error } +func (r *settingRepo) SetSlice(key biz.SettingKey, value []string) error { + setting := new(biz.Setting) + if err := r.db.Where("key = ?", key).First(setting).Error; err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + } + + setting.Key = key + if len(value) == 0 { + setting.Value = "[]" + } else { + b, err := json.Marshal(value) + if err != nil { + return err + } + setting.Value = string(b) + } + + return r.db.Save(setting).Error +} + func (r *settingRepo) Delete(key biz.SettingKey) error { setting := new(biz.Setting) if err := r.db.Where("key = ?", key).Delete(setting).Error; err != nil { @@ -103,6 +168,27 @@ func (r *settingRepo) GetPanelSetting(ctx context.Context) (*request.PanelSettin if err != nil { return nil, err } + twoFA, err := r.GetBool(biz.SettingKeyTwoFA) + if err != nil { + return nil, err + } + loginTimeout, err := r.GetInt(biz.SettingKeyLoginTimeout) + if err != nil { + return nil, err + } + bindDomain, err := r.GetSlice(biz.SettingKeyBindDomain) + if err != nil { + return nil, err + } + bindIP, err := r.GetSlice(biz.SettingKeyBindIP) + if err != nil { + return nil, err + } + bindUA, err := r.GetSlice(biz.SettingKeyBindUA) + if err != nil { + return nil, err + } + websitePath, err := r.Get(biz.SettingKeyWebsitePath) if err != nil { return nil, err @@ -128,19 +214,24 @@ func (r *settingRepo) GetPanelSetting(ctx context.Context) (*request.PanelSettin } return &request.PanelSetting{ - Name: name, - Locale: r.conf.String("app.locale"), - Entrance: r.conf.String("http.entrance"), - OfflineMode: offlineMode, - AutoUpdate: autoUpdate, - WebsitePath: websitePath, - BackupPath: backupPath, - Username: user.Username, - Email: user.Email, - Port: uint(r.conf.Int("http.port")), - HTTPS: r.conf.Bool("http.tls"), - Cert: crt, - Key: key, + Name: name, + Locale: r.conf.String("app.locale"), + Entrance: r.conf.String("http.entrance"), + OfflineMode: offlineMode, + AutoUpdate: autoUpdate, + TwoFA: twoFA, + LoginTimeout: loginTimeout, + BindDomain: bindDomain, + BindIP: bindIP, + BindUA: bindUA, + WebsitePath: websitePath, + BackupPath: backupPath, + Username: user.Username, + Email: user.Email, + Port: uint(r.conf.Int("http.port")), + HTTPS: r.conf.Bool("http.tls"), + Cert: crt, + Key: key, }, nil } @@ -154,6 +245,21 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P if err := r.Set(biz.SettingKeyAutoUpdate, cast.ToString(setting.AutoUpdate)); err != nil { return false, err } + if err := r.Set(biz.SettingKeyLoginTimeout, cast.ToString(setting.LoginTimeout)); err != nil { + return false, err + } + if err := r.Set(biz.SettingKeyTwoFA, cast.ToString(setting.TwoFA)); err != nil { + return false, err + } + if err := r.SetSlice(biz.SettingKeyBindDomain, setting.BindDomain); err != nil { + return false, err + } + if err := r.SetSlice(biz.SettingKeyBindIP, setting.BindIP); err != nil { + return false, err + } + if err := r.SetSlice(biz.SettingKeyBindUA, setting.BindUA); err != nil { + return false, err + } if err := r.Set(biz.SettingKeyWebsitePath, setting.WebsitePath); err != nil { return false, err } diff --git a/internal/http/request/setting.go b/internal/http/request/setting.go index 9ca48756..06d10e7d 100644 --- a/internal/http/request/setting.go +++ b/internal/http/request/setting.go @@ -1,18 +1,23 @@ package request type PanelSetting struct { - Name string `json:"name" validate:"required"` - Locale string `json:"locale" validate:"required"` - Entrance string `json:"entrance" validate:"required"` - OfflineMode bool `json:"offline_mode"` - AutoUpdate bool `json:"auto_update"` - WebsitePath string `json:"website_path" validate:"required"` - BackupPath string `json:"backup_path" validate:"required"` - Username string `json:"username" validate:"required"` - Password string `json:"password" validate:"password"` - Email string `json:"email" validate:"required"` - Port uint `json:"port" validate:"required|min:1|max:65535"` - HTTPS bool `json:"https"` - Cert string `json:"cert" validate:"required"` - Key string `json:"key" validate:"required"` + Name string `json:"name" validate:"required"` + Locale string `json:"locale" validate:"required"` + Entrance string `json:"entrance" validate:"required"` + OfflineMode bool `json:"offline_mode"` + AutoUpdate bool `json:"auto_update"` + TwoFA bool `json:"two_fa"` + LoginTimeout int `json:"login_timeout" validate:"required|min:10|max:43200"` // 登录超时,单位:分 + BindDomain []string `json:"bind_domain"` + BindIP []string `json:"bind_ip"` + BindUA []string `json:"bind_ua"` + WebsitePath string `json:"website_path" validate:"required"` + BackupPath string `json:"backup_path" validate:"required"` + Username string `json:"username" validate:"required"` + Password string `json:"password" validate:"password"` + Email string `json:"email" validate:"required"` + Port uint `json:"port" validate:"required|min:1|max:65535"` + HTTPS bool `json:"https"` + Cert string `json:"cert" validate:"required"` + Key string `json:"key" validate:"required"` } diff --git a/internal/service/cli.go b/internal/service/cli.go index b1a4b0c6..73a81807 100644 --- a/internal/service/cli.go +++ b/internal/service/cli.go @@ -825,6 +825,12 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error { {Key: biz.SettingKeyVersion, Value: app.Version}, {Key: biz.SettingKeyOfflineMode, Value: "false"}, {Key: biz.SettingKeyAutoUpdate, Value: "true"}, + {Key: biz.SettingKeyTwoFA, Value: "false"}, + {Key: biz.SettingKeyTwoFAToken, Value: ""}, + {Key: biz.SettingKeyLoginTimeout, Value: "720"}, + {Key: biz.SettingKeyBindDomain, Value: "[]"}, + {Key: biz.SettingKeyBindIP, Value: "[]"}, + {Key: biz.SettingKeyBindUA, Value: "[]"}, } if err := s.db.Create(&settings).Error; err != nil { return errors.New(s.t.Get("Initialization failed: %v", err))