feat: 分离密码重置和修改密码功能
- 密码重置:用户忘记密码时通过邮箱/短信验证(需开启开关) - 修改密码:已登录用户通过旧密码修改(固定功能,无需配置) - 添加 EnablePasswordReset 开关控制密码重置功能 - PasswordResetMethod 只支持 email/sms 两种验证方式 - 添加短信配置管理功能 - 移除独立的应用邮箱设置页面
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package admin
|
||||
package admin
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
@@ -87,50 +87,60 @@ func handleCreateApplication(c *gin.Context) {
|
||||
userID := c.GetUint("user_id")
|
||||
|
||||
var req struct {
|
||||
Name string `form:"name" json:"name"`
|
||||
Description string `form:"description" json:"description"`
|
||||
BillingType string `form:"billing_type" json:"billing_type"`
|
||||
LoginPolicy string `form:"login_policy" json:"login_policy"`
|
||||
EncryptType string `form:"encrypt_type" json:"encrypt_type"`
|
||||
SecretKey string `form:"secret_key" json:"secret_key"`
|
||||
BindType string `form:"bind_type" json:"bind_type"`
|
||||
MaxDevices string `form:"max_devices" json:"max_devices"`
|
||||
ChangeLimit string `form:"change_limit" json:"change_limit"`
|
||||
ChangeInterval string `form:"change_interval" json:"change_interval"`
|
||||
ChangeExceedAction string `form:"change_exceed_action" json:"change_exceed_action"`
|
||||
ChangeDeductAmount string `form:"change_deduct_amount" json:"change_deduct_amount"`
|
||||
MultiOpenMode string `form:"multi_open_mode" json:"multi_open_mode"`
|
||||
MaxInstances string `form:"max_instances" json:"max_instances"`
|
||||
MultiOpen string `form:"multi_open" json:"multi_open"`
|
||||
EnableTrial string `form:"enable_trial" json:"enable_trial"`
|
||||
TrialBalance string `form:"trial_balance" json:"trial_balance"`
|
||||
TrialDays string `form:"trial_days" json:"trial_days"`
|
||||
EnableFreePeriod string `form:"enable_free_period" json:"enable_free_period"`
|
||||
FreePeriodType string `form:"free_period_type" json:"free_period_type"`
|
||||
FreePeriodStart string `form:"free_period_start" json:"free_period_start"`
|
||||
FreePeriodEnd string `form:"free_period_end" json:"free_period_end"`
|
||||
FreePeriodWeekdays string `form:"free_period_weekdays" json:"free_period_weekdays"`
|
||||
FreePeriodStartTime string `form:"free_period_start_time" json:"free_period_start_time"`
|
||||
FreePeriodEndTime string `form:"free_period_end_time" json:"free_period_end_time"`
|
||||
HeartbeatInterval string `form:"heartbeat_interval" json:"heartbeat_interval"`
|
||||
HeartbeatTimeout string `form:"heartbeat_timeout" json:"heartbeat_timeout"`
|
||||
MaxAttempts string `form:"max_attempts" json:"max_attempts"`
|
||||
LockDuration string `form:"lock_duration" json:"lock_duration"`
|
||||
DeductionMode string `form:"deduction_mode" json:"deduction_mode"`
|
||||
DeductionType string `form:"deduction_type" json:"deduction_type"`
|
||||
DeductionInterval string `form:"deduction_interval" json:"deduction_interval"`
|
||||
DeductionUnit string `form:"deduction_unit" json:"deduction_unit"`
|
||||
DeductionAmount string `form:"deduction_amount" json:"deduction_amount"`
|
||||
DeductionCycle string `form:"deduction_cycle" json:"deduction_cycle"`
|
||||
Name string `form:"name" json:"name"`
|
||||
Description string `form:"description" json:"description"`
|
||||
BillingType string `form:"billing_type" json:"billing_type"`
|
||||
LoginPolicy string `form:"login_policy" json:"login_policy"`
|
||||
EncryptType string `form:"encrypt_type" json:"encrypt_type"`
|
||||
EncryptKey string `form:"encrypt_key" json:"encrypt_key"`
|
||||
BindType string `form:"bind_type" json:"bind_type"`
|
||||
MaxDevices string `form:"max_devices" json:"max_devices"`
|
||||
ChangeLimit string `form:"change_limit" json:"change_limit"`
|
||||
ChangeInterval string `form:"change_interval" json:"change_interval"`
|
||||
ChangeExceedAction string `form:"change_exceed_action" json:"change_exceed_action"`
|
||||
ChangeDeductAmount string `form:"change_deduct_amount" json:"change_deduct_amount"`
|
||||
MultiOpenMode string `form:"multi_open_mode" json:"multi_open_mode"`
|
||||
MaxInstances string `form:"max_instances" json:"max_instances"`
|
||||
EnableTrial string `form:"enable_trial" json:"enable_trial"`
|
||||
TrialBalance string `form:"trial_balance" json:"trial_balance"`
|
||||
TrialDays string `form:"trial_days" json:"trial_days"`
|
||||
EnableFreePeriod string `form:"enable_free_period" json:"enable_free_period"`
|
||||
FreePeriodType string `form:"free_period_type" json:"free_period_type"`
|
||||
FreePeriodStart string `form:"free_period_start" json:"free_period_start"`
|
||||
FreePeriodEnd string `form:"free_period_end" json:"free_period_end"`
|
||||
FreePeriodWeekdays string `form:"free_period_weekdays" json:"free_period_weekdays"`
|
||||
FreePeriodStartTime string `form:"free_period_start_time" json:"free_period_start_time"`
|
||||
FreePeriodEndTime string `form:"free_period_end_time" json:"free_period_end_time"`
|
||||
HeartbeatInterval string `form:"heartbeat_interval" json:"heartbeat_interval"`
|
||||
HeartbeatTimeout string `form:"heartbeat_timeout" json:"heartbeat_timeout"`
|
||||
MaxAttempts string `form:"max_attempts" json:"max_attempts"`
|
||||
LockDuration string `form:"lock_duration" json:"lock_duration"`
|
||||
DeductionMode string `form:"deduction_mode" json:"deduction_mode"`
|
||||
DeductionType string `form:"deduction_type" json:"deduction_type"`
|
||||
DeductionInterval string `form:"deduction_interval" json:"deduction_interval"`
|
||||
DeductionUnit string `form:"deduction_unit" json:"deduction_unit"`
|
||||
DeductionAmount string `form:"deduction_amount" json:"deduction_amount"`
|
||||
DeductionCycle string `form:"deduction_cycle" json:"deduction_cycle"`
|
||||
AllowRegister string `form:"allow_register" json:"allow_register"`
|
||||
EnableLoginVerify string `form:"enable_login_verify" json:"enable_login_verify"`
|
||||
EnableRegisterVerify string `form:"enable_register_verify" json:"enable_register_verify"`
|
||||
EnablePasswordReset string `form:"enable_password_reset" json:"enable_password_reset"`
|
||||
PasswordResetMethod string `form:"password_reset_method" json:"password_reset_method"`
|
||||
PasswordResetEmailID uint `form:"password_reset_email_id" json:"password_reset_email_id"`
|
||||
PasswordResetSmsID uint `form:"password_reset_sms_id" json:"password_reset_sms_id"`
|
||||
Status string `form:"status" json:"status"`
|
||||
}
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
response.Error(c, 400, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
multiOpen := req.MultiOpen == "true"
|
||||
enableTrial := req.EnableTrial == "true"
|
||||
enableFreePeriod := req.EnableFreePeriod == "true"
|
||||
allowRegister := req.AllowRegister != "false"
|
||||
enableLoginVerify := req.EnableLoginVerify == "true"
|
||||
enableRegisterVerify := req.EnableRegisterVerify == "true"
|
||||
enablePasswordReset := req.EnablePasswordReset == "true"
|
||||
|
||||
maxDevices := parseIntWithDefault(req.MaxDevices, 1)
|
||||
changeLimit := parseIntWithDefault(req.ChangeLimit, 3)
|
||||
@@ -147,9 +157,9 @@ func handleCreateApplication(c *gin.Context) {
|
||||
deductionAmount := parseFloatWithDefault(req.DeductionAmount, 1)
|
||||
|
||||
appKey := generateAppKey()
|
||||
secretKey := req.SecretKey
|
||||
if secretKey == "" {
|
||||
secretKey = generateSecretKey()
|
||||
encryptKey := req.EncryptKey
|
||||
if encryptKey == "" {
|
||||
encryptKey = generateSecretKey()
|
||||
}
|
||||
|
||||
encryptType := req.EncryptType
|
||||
@@ -177,44 +187,65 @@ func handleCreateApplication(c *gin.Context) {
|
||||
deductionUnit = req.DeductionCycle
|
||||
}
|
||||
|
||||
passwordResetMethod := req.PasswordResetMethod
|
||||
if passwordResetMethod == "" {
|
||||
passwordResetMethod = "none"
|
||||
}
|
||||
|
||||
var passwordResetEmailID *uint
|
||||
if req.PasswordResetEmailID > 0 {
|
||||
passwordResetEmailID = &req.PasswordResetEmailID
|
||||
}
|
||||
|
||||
var passwordResetSmsID *uint
|
||||
if req.PasswordResetSmsID > 0 {
|
||||
passwordResetSmsID = &req.PasswordResetSmsID
|
||||
}
|
||||
|
||||
app := model.Application{
|
||||
UserID: userID,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
AppKey: appKey,
|
||||
SecretKey: secretKey,
|
||||
BillingType: req.BillingType,
|
||||
LoginPolicy: loginPolicy,
|
||||
EncryptType: encryptType,
|
||||
BindType: req.BindType,
|
||||
MaxDevices: maxDevices,
|
||||
ChangeLimit: changeLimit,
|
||||
ChangeInterval: changeInterval,
|
||||
ChangeExceedAction: changeExceedAction,
|
||||
ChangeDeductAmount: changeDeductAmount,
|
||||
MultiOpenMode: multiOpenMode,
|
||||
MaxInstances: maxInstances,
|
||||
MultiOpen: multiOpen,
|
||||
EnableTrial: enableTrial,
|
||||
TrialBalance: trialBalance,
|
||||
TrialDays: trialDays,
|
||||
EnableFreePeriod: enableFreePeriod,
|
||||
FreePeriodType: req.FreePeriodType,
|
||||
FreePeriodStart: req.FreePeriodStart,
|
||||
FreePeriodEnd: req.FreePeriodEnd,
|
||||
FreePeriodWeekdays: req.FreePeriodWeekdays,
|
||||
FreePeriodStartTime: req.FreePeriodStartTime,
|
||||
FreePeriodEndTime: req.FreePeriodEndTime,
|
||||
HeartbeatInterval: heartbeatInterval,
|
||||
HeartbeatTimeout: heartbeatTimeout,
|
||||
MaxAttempts: maxAttempts,
|
||||
LockDuration: lockDuration,
|
||||
DeductionMode: req.DeductionMode,
|
||||
DeductionType: req.DeductionType,
|
||||
DeductionInterval: deductionInterval,
|
||||
DeductionUnit: deductionUnit,
|
||||
DeductionAmount: deductionAmount,
|
||||
Status: "active",
|
||||
UserID: userID,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
AppKey: appKey,
|
||||
EncryptKey: encryptKey,
|
||||
BillingType: req.BillingType,
|
||||
LoginPolicy: loginPolicy,
|
||||
EncryptType: encryptType,
|
||||
BindType: req.BindType,
|
||||
MaxDevices: maxDevices,
|
||||
ChangeLimit: changeLimit,
|
||||
ChangeInterval: changeInterval,
|
||||
ChangeExceedAction: changeExceedAction,
|
||||
ChangeDeductAmount: changeDeductAmount,
|
||||
MultiOpenMode: multiOpenMode,
|
||||
MaxInstances: maxInstances,
|
||||
EnableTrial: enableTrial,
|
||||
TrialBalance: trialBalance,
|
||||
TrialDays: trialDays,
|
||||
EnableFreePeriod: enableFreePeriod,
|
||||
FreePeriodType: req.FreePeriodType,
|
||||
FreePeriodStart: req.FreePeriodStart,
|
||||
FreePeriodEnd: req.FreePeriodEnd,
|
||||
FreePeriodWeekdays: req.FreePeriodWeekdays,
|
||||
FreePeriodStartTime: req.FreePeriodStartTime,
|
||||
FreePeriodEndTime: req.FreePeriodEndTime,
|
||||
HeartbeatInterval: heartbeatInterval,
|
||||
HeartbeatTimeout: heartbeatTimeout,
|
||||
MaxAttempts: maxAttempts,
|
||||
LockDuration: lockDuration,
|
||||
DeductionMode: req.DeductionMode,
|
||||
DeductionType: req.DeductionType,
|
||||
DeductionInterval: deductionInterval,
|
||||
DeductionUnit: deductionUnit,
|
||||
DeductionAmount: deductionAmount,
|
||||
AllowRegister: allowRegister,
|
||||
EnableLoginVerify: enableLoginVerify,
|
||||
EnableRegisterVerify: enableRegisterVerify,
|
||||
EnablePasswordReset: enablePasswordReset,
|
||||
PasswordResetMethod: passwordResetMethod,
|
||||
PasswordResetEmailID: passwordResetEmailID,
|
||||
PasswordResetSmsID: passwordResetSmsID,
|
||||
Status: "active",
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&app).Error; err != nil {
|
||||
@@ -264,43 +295,50 @@ func generateSecretKey() string {
|
||||
func handleUpdateApplication(c *gin.Context) {
|
||||
userID := c.GetUint("user_id")
|
||||
var req struct {
|
||||
Name string `form:"name" json:"name"`
|
||||
Description string `form:"description" json:"description"`
|
||||
BillingType string `form:"billing_type" json:"billing_type"`
|
||||
LoginPolicy string `form:"login_policy" json:"login_policy"`
|
||||
AllowRegister bool `form:"allow_register" json:"allow_register"`
|
||||
RegisterMethods string `form:"register_methods" json:"register_methods"`
|
||||
EncryptType string `form:"encrypt_type" json:"encrypt_type"`
|
||||
SecretKey string `form:"secret_key" json:"secret_key"`
|
||||
BindType string `form:"bind_type" json:"bind_type"`
|
||||
MaxDevices int `form:"max_devices" json:"max_devices"`
|
||||
ChangeLimit int `form:"change_limit" json:"change_limit"`
|
||||
ChangeInterval int `form:"change_interval" json:"change_interval"`
|
||||
ChangeExceedAction string `form:"change_exceed_action" json:"change_exceed_action"`
|
||||
ChangeDeductAmount float64 `form:"change_deduct_amount" json:"change_deduct_amount"`
|
||||
MultiOpenMode string `form:"multi_open_mode" json:"multi_open_mode"`
|
||||
MaxInstances int `form:"max_instances" json:"max_instances"`
|
||||
MultiOpen bool `form:"multi_open" json:"multi_open"`
|
||||
EnableTrial bool `form:"enable_trial" json:"enable_trial"`
|
||||
TrialBalance float64 `form:"trial_balance" json:"trial_balance"`
|
||||
TrialDays int `form:"trial_days" json:"trial_days"`
|
||||
EnableFreePeriod bool `form:"enable_free_period" json:"enable_free_period"`
|
||||
FreePeriodType string `form:"free_period_type" json:"free_period_type"`
|
||||
FreePeriodStart string `form:"free_period_start" json:"free_period_start"`
|
||||
FreePeriodEnd string `form:"free_period_end" json:"free_period_end"`
|
||||
FreePeriodWeekdays string `form:"free_period_weekdays" json:"free_period_weekdays"`
|
||||
FreePeriodStartTime string `form:"free_period_start_time" json:"free_period_start_time"`
|
||||
FreePeriodEndTime string `form:"free_period_end_time" json:"free_period_end_time"`
|
||||
HeartbeatInterval int `form:"heartbeat_interval" json:"heartbeat_interval"`
|
||||
HeartbeatTimeout int `form:"heartbeat_timeout" json:"heartbeat_timeout"`
|
||||
MaxAttempts int `form:"max_attempts" json:"max_attempts"`
|
||||
LockDuration int `form:"lock_duration" json:"lock_duration"`
|
||||
Status string `form:"status" json:"status"`
|
||||
DeductionMode string `form:"deduction_mode" json:"deduction_mode"`
|
||||
DeductionType string `form:"deduction_type" json:"deduction_type"`
|
||||
DeductionInterval int `form:"deduction_interval" json:"deduction_interval"`
|
||||
DeductionUnit string `form:"deduction_unit" json:"deduction_unit"`
|
||||
DeductionAmount float64 `form:"deduction_amount" json:"deduction_amount"`
|
||||
Name string `form:"name" json:"name"`
|
||||
Description string `form:"description" json:"description"`
|
||||
BillingType string `form:"billing_type" json:"billing_type"`
|
||||
LoginPolicy string `form:"login_policy" json:"login_policy"`
|
||||
AllowRegister bool `form:"allow_register" json:"allow_register"`
|
||||
EnableLoginVerify bool `form:"enable_login_verify" json:"enable_login_verify"`
|
||||
EnableRegisterVerify bool `form:"enable_register_verify" json:"enable_register_verify"`
|
||||
VerifyMethod string `form:"verify_method" json:"verify_method"`
|
||||
EmailConfigID *uint `form:"email_config_id" json:"email_config_id"`
|
||||
SmsConfigID *uint `form:"sms_config_id" json:"sms_config_id"`
|
||||
EncryptType string `form:"encrypt_type" json:"encrypt_type"`
|
||||
EncryptKey string `form:"encrypt_key" json:"encrypt_key"`
|
||||
BindType string `form:"bind_type" json:"bind_type"`
|
||||
MaxDevices int `form:"max_devices" json:"max_devices"`
|
||||
ChangeLimit int `form:"change_limit" json:"change_limit"`
|
||||
ChangeInterval int `form:"change_interval" json:"change_interval"`
|
||||
ChangeExceedAction string `form:"change_exceed_action" json:"change_exceed_action"`
|
||||
ChangeDeductAmount float64 `form:"change_deduct_amount" json:"change_deduct_amount"`
|
||||
MultiOpenMode string `form:"multi_open_mode" json:"multi_open_mode"`
|
||||
MaxInstances int `form:"max_instances" json:"max_instances"`
|
||||
EnableTrial bool `form:"enable_trial" json:"enable_trial"`
|
||||
TrialBalance float64 `form:"trial_balance" json:"trial_balance"`
|
||||
TrialDays int `form:"trial_days" json:"trial_days"`
|
||||
EnableFreePeriod bool `form:"enable_free_period" json:"enable_free_period"`
|
||||
FreePeriodType string `form:"free_period_type" json:"free_period_type"`
|
||||
FreePeriodStart string `form:"free_period_start" json:"free_period_start"`
|
||||
FreePeriodEnd string `form:"free_period_end" json:"free_period_end"`
|
||||
FreePeriodWeekdays string `form:"free_period_weekdays" json:"free_period_weekdays"`
|
||||
FreePeriodStartTime string `form:"free_period_start_time" json:"free_period_start_time"`
|
||||
FreePeriodEndTime string `form:"free_period_end_time" json:"free_period_end_time"`
|
||||
HeartbeatInterval int `form:"heartbeat_interval" json:"heartbeat_interval"`
|
||||
HeartbeatTimeout int `form:"heartbeat_timeout" json:"heartbeat_timeout"`
|
||||
MaxAttempts int `form:"max_attempts" json:"max_attempts"`
|
||||
LockDuration int `form:"lock_duration" json:"lock_duration"`
|
||||
Status string `form:"status" json:"status"`
|
||||
DeductionMode string `form:"deduction_mode" json:"deduction_mode"`
|
||||
DeductionType string `form:"deduction_type" json:"deduction_type"`
|
||||
DeductionInterval int `form:"deduction_interval" json:"deduction_interval"`
|
||||
DeductionUnit string `form:"deduction_unit" json:"deduction_unit"`
|
||||
DeductionAmount float64 `form:"deduction_amount" json:"deduction_amount"`
|
||||
EnablePasswordReset bool `form:"enable_password_reset" json:"enable_password_reset"`
|
||||
PasswordResetMethod string `form:"password_reset_method" json:"password_reset_method"`
|
||||
PasswordResetEmailID *uint `form:"password_reset_email_id" json:"password_reset_email_id"`
|
||||
PasswordResetSmsID *uint `form:"password_reset_sms_id" json:"password_reset_sms_id"`
|
||||
}
|
||||
|
||||
contentType := c.GetHeader("Content-Type")
|
||||
@@ -315,7 +353,7 @@ func handleUpdateApplication(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("更新应用请求: EncryptType=%s, SecretKey=%s\n", req.EncryptType, req.SecretKey)
|
||||
fmt.Printf("更新应用请求: EncryptType=%s, EncryptKey=%s\n", req.EncryptType, req.EncryptKey)
|
||||
|
||||
id := c.Param("id")
|
||||
var app model.Application
|
||||
@@ -324,17 +362,21 @@ func handleUpdateApplication(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("更新应用前: ID=%d, EncryptType=%s, SecretKey=%s\n", app.ID, app.EncryptType, app.SecretKey)
|
||||
fmt.Printf("更新应用前: ID=%d, EncryptType=%s, EncryptKey=%s\n", app.ID, app.EncryptType, app.EncryptKey)
|
||||
|
||||
app.Name = req.Name
|
||||
app.Description = req.Description
|
||||
app.BillingType = req.BillingType
|
||||
app.LoginPolicy = req.LoginPolicy
|
||||
app.AllowRegister = req.AllowRegister
|
||||
app.RegisterMethods = req.RegisterMethods
|
||||
app.EnableLoginVerify = req.EnableLoginVerify
|
||||
app.EnableRegisterVerify = req.EnableRegisterVerify
|
||||
app.VerifyMethod = req.VerifyMethod
|
||||
app.EmailConfigID = req.EmailConfigID
|
||||
app.SmsConfigID = req.SmsConfigID
|
||||
app.EncryptType = req.EncryptType
|
||||
if req.SecretKey != "" {
|
||||
app.SecretKey = req.SecretKey
|
||||
if req.EncryptKey != "" {
|
||||
app.EncryptKey = req.EncryptKey
|
||||
}
|
||||
app.BindType = req.BindType
|
||||
app.MaxDevices = req.MaxDevices
|
||||
@@ -344,7 +386,6 @@ func handleUpdateApplication(c *gin.Context) {
|
||||
app.ChangeDeductAmount = req.ChangeDeductAmount
|
||||
app.MultiOpenMode = req.MultiOpenMode
|
||||
app.MaxInstances = req.MaxInstances
|
||||
app.MultiOpen = req.MultiOpen
|
||||
app.EnableTrial = req.EnableTrial
|
||||
app.TrialBalance = req.TrialBalance
|
||||
app.TrialDays = req.TrialDays
|
||||
@@ -373,6 +414,12 @@ func handleUpdateApplication(c *gin.Context) {
|
||||
app.DeductionInterval = req.DeductionInterval
|
||||
app.DeductionUnit = req.DeductionUnit
|
||||
app.DeductionAmount = req.DeductionAmount
|
||||
app.EnablePasswordReset = req.EnablePasswordReset
|
||||
if req.PasswordResetMethod != "" {
|
||||
app.PasswordResetMethod = req.PasswordResetMethod
|
||||
}
|
||||
app.PasswordResetEmailID = req.PasswordResetEmailID
|
||||
app.PasswordResetSmsID = req.PasswordResetSmsID
|
||||
|
||||
file, header, err := c.Request.FormFile("icon")
|
||||
if err == nil {
|
||||
@@ -398,7 +445,7 @@ func handleUpdateApplication(c *gin.Context) {
|
||||
app.IconURL = "/uploads/icons/" + filename
|
||||
}
|
||||
|
||||
fmt.Printf("更新应用: ID=%d, EncryptType=%s, SecretKey=%s\n", app.ID, app.EncryptType, app.SecretKey)
|
||||
fmt.Printf("更新应用: ID=%d, EncryptType=%s, EncryptKey=%s\n", app.ID, app.EncryptType, app.EncryptKey)
|
||||
|
||||
if err := database.DB.Save(&app).Error; err != nil {
|
||||
response.Error(c, 500, "更新应用失败")
|
||||
|
||||
@@ -26,6 +26,7 @@ func SetupRoutes(r *gin.RouterGroup) {
|
||||
SetupEmailRoutes(r)
|
||||
SetupSystemSettingsRoutes(r)
|
||||
SetupEmailConfigRoutes(r)
|
||||
SetupSmsConfigRoutes(r)
|
||||
SetupStorageConfigRoutes(r)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package admin
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -46,9 +46,10 @@ func handleGetEmailConfig(c *gin.Context) {
|
||||
database.DB.Where("application_id = ?", app.ID).First(&smtpConfig)
|
||||
|
||||
result := gin.H{
|
||||
"enable_email_verify": app.EnableEmailVerify,
|
||||
"require_email_verify": app.RequireEmailVerify,
|
||||
"enable_password_reset": app.EnablePasswordReset,
|
||||
"enable_login_verify": app.EnableLoginVerify,
|
||||
"enable_register_verify": app.EnableRegisterVerify,
|
||||
"enable_password_reset": app.EnablePasswordReset,
|
||||
"password_reset_method": app.PasswordResetMethod,
|
||||
"permission": gin.H{
|
||||
"allow_email": permission.AllowEmail,
|
||||
},
|
||||
@@ -90,10 +91,11 @@ func handleUpdateEmailConfig(c *gin.Context) {
|
||||
}
|
||||
|
||||
var req struct {
|
||||
EnableEmailVerify bool `json:"enable_email_verify"`
|
||||
RequireEmailVerify bool `json:"require_email_verify"`
|
||||
EnablePasswordReset bool `json:"enable_password_reset"`
|
||||
SMTPConfig *struct {
|
||||
EnableEmailVerify bool `json:"enable_email_verify"`
|
||||
RequireEmailVerify bool `json:"require_email_verify"`
|
||||
EnablePasswordReset bool `json:"enable_password_reset"`
|
||||
PasswordResetMethod string `json:"password_reset_method"`
|
||||
SMTPConfig *struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
User string `json:"user"`
|
||||
@@ -110,9 +112,10 @@ func handleUpdateEmailConfig(c *gin.Context) {
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"enable_email_verify": req.EnableEmailVerify,
|
||||
"require_email_verify": req.RequireEmailVerify,
|
||||
"enable_password_reset": req.EnablePasswordReset,
|
||||
"enable_email_verify": req.EnableEmailVerify,
|
||||
"require_email_verify": req.RequireEmailVerify,
|
||||
"enable_password_reset": req.EnablePasswordReset,
|
||||
"password_reset_method": req.PasswordResetMethod,
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&app).Updates(updates).Error; err != nil {
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"verification-platform-backend/internal/database"
|
||||
"verification-platform-backend/internal/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupSmsConfigRoutes(r *gin.RouterGroup) {
|
||||
smsConfigs := r.Group("/sms-configs")
|
||||
{
|
||||
smsConfigs.GET("", handleGetSmsConfigs)
|
||||
smsConfigs.POST("", handleCreateSmsConfig)
|
||||
smsConfigs.GET("/:id", handleGetSmsConfig)
|
||||
smsConfigs.PUT("/:id", handleUpdateSmsConfig)
|
||||
smsConfigs.DELETE("/:id", handleDeleteSmsConfig)
|
||||
smsConfigs.PUT("/:id/status", handleUpdateSmsConfigStatus)
|
||||
smsConfigs.POST("/:id/test", handleTestSmsConfig)
|
||||
smsConfigs.PUT("/batch/status", handleBatchUpdateSmsConfigStatus)
|
||||
smsConfigs.DELETE("/batch", handleBatchDeleteSmsConfigs)
|
||||
}
|
||||
}
|
||||
|
||||
func handleGetSmsConfigs(c *gin.Context) {
|
||||
var configs []model.SmsConfig
|
||||
database.DB.Order("id desc").Find(&configs)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"data": gin.H{
|
||||
"sms_configs": configs,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type CreateSmsConfigRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Type string `json:"type" binding:"required"`
|
||||
Config string `json:"config"`
|
||||
Status string `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func handleCreateSmsConfig(c *gin.Context) {
|
||||
var req CreateSmsConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "无效的请求数据",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
status := "active"
|
||||
if req.Status != "" {
|
||||
status = req.Status
|
||||
}
|
||||
|
||||
config := model.SmsConfig{
|
||||
Name: req.Name,
|
||||
Type: req.Type,
|
||||
Config: req.Config,
|
||||
Status: status,
|
||||
Remark: req.Remark,
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&config).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": "创建失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": config,
|
||||
})
|
||||
}
|
||||
|
||||
func handleGetSmsConfig(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var config model.SmsConfig
|
||||
if err := database.DB.First(&config, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": 404,
|
||||
"message": "短信配置不存在",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"data": config,
|
||||
})
|
||||
}
|
||||
|
||||
type UpdateSmsConfigRequest struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Config string `json:"config"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func handleUpdateSmsConfig(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var config model.SmsConfig
|
||||
if err := database.DB.First(&config, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": 404,
|
||||
"message": "短信配置不存在",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req UpdateSmsConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "无效的请求数据",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "" {
|
||||
config.Name = req.Name
|
||||
}
|
||||
if req.Type != "" {
|
||||
config.Type = req.Type
|
||||
}
|
||||
if req.Config != "" {
|
||||
config.Config = req.Config
|
||||
}
|
||||
config.Remark = req.Remark
|
||||
|
||||
if err := database.DB.Save(&config).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": "更新失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "更新成功",
|
||||
"data": config,
|
||||
})
|
||||
}
|
||||
|
||||
func handleDeleteSmsConfig(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var config model.SmsConfig
|
||||
if err := database.DB.First(&config, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": 404,
|
||||
"message": "短信配置不存在",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := database.DB.Delete(&config).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": "删除失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "删除成功",
|
||||
})
|
||||
}
|
||||
|
||||
type UpdateSmsConfigStatusRequest struct {
|
||||
Status string `json:"status" binding:"required"`
|
||||
}
|
||||
|
||||
func handleUpdateSmsConfigStatus(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var config model.SmsConfig
|
||||
if err := database.DB.First(&config, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": 404,
|
||||
"message": "短信配置不存在",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req UpdateSmsConfigStatusRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "无效的请求数据",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
config.Status = req.Status
|
||||
if err := database.DB.Save(&config).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": "更新失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
type TestSmsConfigRequest struct {
|
||||
Phone string `json:"phone" binding:"required"`
|
||||
}
|
||||
|
||||
func handleTestSmsConfig(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var config model.SmsConfig
|
||||
if err := database.DB.First(&config, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": 404,
|
||||
"message": "短信配置不存在",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req TestSmsConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "请输入有效的手机号码",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "测试短信已发送",
|
||||
})
|
||||
}
|
||||
|
||||
type BatchUpdateSmsConfigStatusRequest struct {
|
||||
IDs []uint `json:"ids"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func handleBatchUpdateSmsConfigStatus(c *gin.Context) {
|
||||
var req BatchUpdateSmsConfigStatusRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Status != "active" && req.Status != "inactive" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "无效的状态",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.IDs) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "请选择要更新的短信配置",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&model.SmsConfig{}).Where("id IN ?", req.IDs).Update("status", req.Status).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": "批量更新失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "批量更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
type BatchDeleteSmsConfigsRequest struct {
|
||||
IDs []uint `json:"ids"`
|
||||
}
|
||||
|
||||
func handleBatchDeleteSmsConfigs(c *gin.Context) {
|
||||
var req BatchDeleteSmsConfigsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.IDs) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "请选择要删除的短信配置",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := database.DB.Where("id IN ?", req.IDs).Delete(&model.SmsConfig{}).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": "批量删除失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "批量删除成功",
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user