diff --git a/api/rule/rule.go b/api/rule/rule.go index a4125f8..69bb16e 100644 --- a/api/rule/rule.go +++ b/api/rule/rule.go @@ -65,6 +65,15 @@ func HandleCreateRule(c *gin.Context) { return } + // 检查关联账号和 Timer 是否存在(可以没有关联账号) + if exist, err := checkRuleConfigAccountAndTimerExist(newRule); err != nil { + c.JSON(500, gin.H{"code": 500, "data": "服务器内部错误"}) + return + } else if !exist { + c.JSON(400, gin.H{"code": 400, "data": "关联的账户或Timer不存在"}) + return + } + // 规则校验 validatorRegistry := ruleConfigChecker.InitValidatorRegistry() if err := validatorRegistry.Validate(newRule.Type, newRule.ConfigJson); err != nil { @@ -82,6 +91,79 @@ func HandleCreateRule(c *gin.Context) { c.JSON(200, gin.H{"code": 200, "data": "规则创建成功"}) } +// 编辑规则 +func HandleEditRule(c *gin.Context) { + gormDB, err := db.GetGormDB() + if err != nil { + c.JSON(500, gin.H{"code": 500, "data": "服务器内部错误"}) + return + } + + userInfo, err := user.GetUserInfoByGinCtx(c) + if err != nil { + c.JSON(401, gin.H{"code": 401, "data": "获取用户信息失败"}) + return + } + + ruleID, err := strconv.Atoi(c.Param("ruleID")) + if err != nil { + c.JSON(400, gin.H{"code": 400, "data": "规则 ID 格式错误"}) + return + } + var rule model.Rule + result := gormDB.Where("id = ? AND uid = ?", ruleID, userInfo.ID).First(&rule) + if result.Error != nil { + c.JSON(404, gin.H{"code": 404, "data": "规则不存在"}) + return + } + + var updatedRule model.Rule + if err := c.BindJSON(&updatedRule); err != nil { + c.JSON(400, gin.H{"code": 400, "data": "输入参数错误"}) + return + } + + if updatedRule.Type == "" { + c.JSON(400, gin.H{"code": 400, "data": "规则类型不能为空"}) + return + } + + if updatedRule.Name == "" { + c.JSON(400, gin.H{"code": 400, "data": "规则名称不能为空"}) + return + } + + // 检查关联账号和 Timer 是否存在(可以没有关联账号) + if exist, err := checkRuleConfigAccountAndTimerExist(updatedRule); err != nil { + c.JSON(500, gin.H{"code": 500, "data": "服务器内部错误"}) + return + } else if !exist { + c.JSON(400, gin.H{"code": 400, "data": "关联的账户或Timer不存在"}) + return + } + + // 规则校验 + validatorRegistry := ruleConfigChecker.InitValidatorRegistry() + if err := validatorRegistry.Validate(updatedRule.Type, updatedRule.ConfigJson); err != nil { + c.JSON(400, gin.H{"code": 400, "data": fmt.Sprintf("规则配置验证失败: %s", err.Error())}) + return + } + + rule.Name = updatedRule.Name + rule.Type = updatedRule.Type + rule.ConfigJson = updatedRule.ConfigJson + rule.AccountID = updatedRule.AccountID + rule.TimerID = updatedRule.TimerID + + result = gormDB.Save(&rule) + if result.Error != nil { + c.JSON(500, gin.H{"code": 500, "data": "更新规则失败"}) + return + } + + c.JSON(200, gin.H{"code": 200, "data": "规则更新成功"}) +} + // 根据删除规则 func HandleDeleteRule(c *gin.Context) { userInfo, err := user.GetUserInfoByGinCtx(c) diff --git a/api/rule/tool.go b/api/rule/tool.go index 19142aa..3b10125 100644 --- a/api/rule/tool.go +++ b/api/rule/tool.go @@ -15,3 +15,38 @@ func DeleteRuleByID(id uint, uid uint) error { result := gormDB.Where("id = ? AND uid = ?", id, uid).Delete(&model.Rule{}) return result.Error } + +// 检查关联账号和 Timer 是否存在(可以没有关联账号) +func checkRuleConfigAccountAndTimerExist(rule model.Rule) (exist bool, err error) { + gormDB, err := db.GetGormDB() + if err != nil { + return false, err + } + + if rule.TimerID == 0 { + return false, nil + } + + var count int64 + if rule.AccountID != 0 { + result := gormDB.Model(&model.Account{}).Where("id = ? AND uid = ?", rule.AccountID, rule.UID).Count(&count) + if result.Error != nil { + return false, result.Error + } + if count == 0 { + return false, nil + } + } + + if rule.TimerID != 0 { + result := gormDB.Model(&model.Timer{}).Where("id = ? AND uid = ?", rule.TimerID, rule.UID).Count(&count) + if result.Error != nil { + return false, result.Error + } + if count == 0 { + return false, nil + } + } + + return true, nil +} diff --git a/internal/ruleConfigChecker/bilibili.go b/drivers/bilibili/ruleConfigChecker.go similarity index 82% rename from internal/ruleConfigChecker/bilibili.go rename to drivers/bilibili/ruleConfigChecker.go index c5f3f59..06e0109 100644 --- a/internal/ruleConfigChecker/bilibili.go +++ b/drivers/bilibili/ruleConfigChecker.go @@ -1,10 +1,8 @@ -package ruleConfigChecker +package bilibili import ( "encoding/json" "fmt" - - "github.com/ssdomei232/goodBaby/drivers/bilibili" ) // BilibiliDynamicRuleValidator B站动态规则验证器 @@ -15,7 +13,7 @@ func (v *BilibiliDynamicRuleValidator) GetType() string { } func (v *BilibiliDynamicRuleValidator) Validate(configJSON string) error { - var config bilibili.BiliDynamicConfig + var config BiliDynamicConfig if err := json.Unmarshal([]byte(configJSON), &config); err != nil { return fmt.Errorf("解析B站动态规则配置失败: %v", err) } diff --git a/handler/runner/bilibili.go b/drivers/bilibili/runner.go similarity index 79% rename from handler/runner/bilibili.go rename to drivers/bilibili/runner.go index 71fe552..07e34e4 100644 --- a/handler/runner/bilibili.go +++ b/drivers/bilibili/runner.go @@ -1,9 +1,8 @@ -package runner +package bilibili import ( "log" - "github.com/ssdomei232/goodBaby/drivers/bilibili" "github.com/ssdomei232/goodBaby/model" ) @@ -17,7 +16,7 @@ func (e *BilibiliDynamicExecutor) GetType() string { func (e *BilibiliDynamicExecutor) Execute(rule *model.Rule) error { log.Printf("执行B站动态规则: %s (ID: %d)", rule.Name, rule.ID) - bilibili.SendBiliDynamicMsg(rule) + SendBiliDynamicMsg(rule) return nil } diff --git a/internal/ruleConfigChecker/dingtalk.go b/drivers/dingtalk/ruleConfigChecker.go similarity index 81% rename from internal/ruleConfigChecker/dingtalk.go rename to drivers/dingtalk/ruleConfigChecker.go index c75c3db..1fc66f7 100644 --- a/internal/ruleConfigChecker/dingtalk.go +++ b/drivers/dingtalk/ruleConfigChecker.go @@ -1,10 +1,8 @@ -package ruleConfigChecker +package dingtalk import ( "encoding/json" "fmt" - - "github.com/ssdomei232/goodBaby/drivers/dingtalk" ) // DingTalkRuleValidator 钉钉规则验证器 @@ -15,7 +13,7 @@ func (v *DingTalkRuleValidator) GetType() string { } func (v *DingTalkRuleValidator) Validate(configJSON string) error { - var config dingtalk.DingTalkConfig + var config DingTalkConfig if err := json.Unmarshal([]byte(configJSON), &config); err != nil { return fmt.Errorf("解析钉钉规则配置失败: %v", err) } diff --git a/internal/ruleConfigChecker/email.go b/drivers/email/ruleConfigChecker.go similarity index 89% rename from internal/ruleConfigChecker/email.go rename to drivers/email/ruleConfigChecker.go index 373fb49..9f9cf19 100644 --- a/internal/ruleConfigChecker/email.go +++ b/drivers/email/ruleConfigChecker.go @@ -1,11 +1,9 @@ -package ruleConfigChecker +package email import ( "encoding/json" "fmt" "net/mail" - - "github.com/ssdomei232/goodBaby/drivers/email" ) // EmailRuleValidator 邮件规则验证器 @@ -16,7 +14,7 @@ func (v *EmailRuleValidator) GetType() string { } func (v *EmailRuleValidator) Validate(configJSON string) error { - var config email.EmailRule + var config EmailRule if err := json.Unmarshal([]byte(configJSON), &config); err != nil { return fmt.Errorf("解析邮件规则配置失败: %v", err) } diff --git a/handler/runner/email.go b/drivers/email/runner.go similarity index 79% rename from handler/runner/email.go rename to drivers/email/runner.go index 7c0500c..8cd47ac 100644 --- a/handler/runner/email.go +++ b/drivers/email/runner.go @@ -1,9 +1,8 @@ -package runner +package email import ( "log" - "github.com/ssdomei232/goodBaby/drivers/email" "github.com/ssdomei232/goodBaby/model" ) @@ -17,7 +16,7 @@ func (e *EmailExecutor) GetType() string { func (e *EmailExecutor) Execute(rule *model.Rule) error { log.Printf("执行邮件规则: %s (ID: %d)", rule.Name, rule.ID) - email.SendMail(rule) + SendMail(rule) return nil } diff --git a/drivers/github/ruleConfigChecker.go b/drivers/github/ruleConfigChecker.go new file mode 100644 index 0000000..7cb1d1c --- /dev/null +++ b/drivers/github/ruleConfigChecker.go @@ -0,0 +1,25 @@ +package github + +import ( + "encoding/json" + "fmt" +) + +type GithubMakeRepositoryPublicRuleValidator struct{} + +func (v *GithubMakeRepositoryPublicRuleValidator) GetType() string { + return "github_make_repository_public" +} + +func (v *GithubMakeRepositoryPublicRuleValidator) Validate(configJSON string) error { + var config GithubReposConfig + if err := json.Unmarshal([]byte(configJSON), &config); err != nil { + return fmt.Errorf("解析 GitHub 规则配置失败: %v", err) + } + + if len(config.Repos) == 0 { + return fmt.Errorf("GitHub 规则配置错误: 至少需要指定一个仓库") + } + + return nil +} diff --git a/handler/runner/github.go b/drivers/github/runner.go similarity index 81% rename from handler/runner/github.go rename to drivers/github/runner.go index 4a8cc38..6069ebc 100644 --- a/handler/runner/github.go +++ b/drivers/github/runner.go @@ -1,9 +1,8 @@ -package runner +package github import ( "log" - "github.com/ssdomei232/goodBaby/drivers/github" "github.com/ssdomei232/goodBaby/model" ) @@ -17,7 +16,7 @@ func (e *GithubMakeRepoPublicExecutor) GetType() string { func (e *GithubMakeRepoPublicExecutor) Execute(rule *model.Rule) error { log.Printf("执行GitHub仓库公开规则: %s (ID: %d)", rule.Name, rule.ID) - github.MakeRepositoryPublic(rule) + MakeRepositoryPublic(rule) return nil } diff --git a/internal/ruleConfigChecker/onebot.go b/drivers/onebot/ruleConfigChecker.go similarity index 84% rename from internal/ruleConfigChecker/onebot.go rename to drivers/onebot/ruleConfigChecker.go index e10e7fa..18eebdc 100644 --- a/internal/ruleConfigChecker/onebot.go +++ b/drivers/onebot/ruleConfigChecker.go @@ -1,10 +1,8 @@ -package ruleConfigChecker +package onebot import ( "encoding/json" "fmt" - - "github.com/ssdomei232/goodBaby/drivers/onebot" ) // OneBotRuleValidator OneBot规则验证器 @@ -15,7 +13,7 @@ func (v *OneBotRuleValidator) GetType() string { } func (v *OneBotRuleValidator) Validate(configJSON string) error { - var config onebot.OneBotConfig + var config OneBotConfig if err := json.Unmarshal([]byte(configJSON), &config); err != nil { return fmt.Errorf("解析OneBot规则配置失败: %v", err) } diff --git a/handler/runner/onebot.go b/drivers/onebot/runner.go similarity index 78% rename from handler/runner/onebot.go rename to drivers/onebot/runner.go index 2bddbeb..c8c3026 100644 --- a/handler/runner/onebot.go +++ b/drivers/onebot/runner.go @@ -1,9 +1,8 @@ -package runner +package onebot import ( "log" - "github.com/ssdomei232/goodBaby/drivers/onebot" "github.com/ssdomei232/goodBaby/model" ) @@ -17,7 +16,7 @@ func (e *OneBotExecutor) GetType() string { func (e *OneBotExecutor) Execute(rule *model.Rule) error { log.Printf("执行OneBot规则: %s (ID: %d)", rule.Name, rule.ID) - onebot.SendOneBotMsg(rule) + SendOneBotMsg(rule) return nil } diff --git a/handler/runner/interface.go b/handler/runner/interface.go index 408fc01..c52c23e 100644 --- a/handler/runner/interface.go +++ b/handler/runner/interface.go @@ -3,6 +3,10 @@ package runner import ( "fmt" + "github.com/ssdomei232/goodBaby/drivers/bilibili" + "github.com/ssdomei232/goodBaby/drivers/email" + "github.com/ssdomei232/goodBaby/drivers/github" + "github.com/ssdomei232/goodBaby/drivers/onebot" "github.com/ssdomei232/goodBaby/model" ) @@ -57,10 +61,10 @@ func InitExecutorRegistry() *ExecutorRegistry { registry := NewExecutorRegistry() // 注册所有规则执行器 - registry.Register(&BilibiliDynamicExecutor{}) - registry.Register(&EmailExecutor{}) - registry.Register(&GithubMakeRepoPublicExecutor{}) - registry.Register(&OneBotExecutor{}) + registry.Register(&bilibili.BilibiliDynamicExecutor{}) + registry.Register(&email.EmailExecutor{}) + registry.Register(&github.GithubMakeRepoPublicExecutor{}) + registry.Register(&onebot.OneBotExecutor{}) // 未来添加新规则类型时,在这里注册即可 globalExecutorRegistry = registry diff --git a/internal/ruleConfigChecker/ruleConfigChecker.go b/internal/ruleConfigChecker/interface.go similarity index 79% rename from internal/ruleConfigChecker/ruleConfigChecker.go rename to internal/ruleConfigChecker/interface.go index 983719f..44662cb 100644 --- a/internal/ruleConfigChecker/ruleConfigChecker.go +++ b/internal/ruleConfigChecker/interface.go @@ -59,16 +59,3 @@ func (vr *ValidatorRegistry) GetSupportedTypes() []string { } return types } - -// InitValidatorRegistry 初始化验证器注册表并注册所有验证器 -func InitValidatorRegistry() *ValidatorRegistry { - registry := NewValidatorRegistry() - - // 注册所有规则验证器 - registry.Register(&BilibiliDynamicRuleValidator{}) - registry.Register(&EmailRuleValidator{}) - registry.Register(&OneBotRuleValidator{}) - registry.Register(&DingTalkRuleValidator{}) - - return registry -} diff --git a/internal/ruleConfigChecker/reg.go b/internal/ruleConfigChecker/reg.go new file mode 100644 index 0000000..49dbf36 --- /dev/null +++ b/internal/ruleConfigChecker/reg.go @@ -0,0 +1,23 @@ +package ruleConfigChecker + +import ( + "github.com/ssdomei232/goodBaby/drivers/bilibili" + "github.com/ssdomei232/goodBaby/drivers/dingtalk" + "github.com/ssdomei232/goodBaby/drivers/email" + "github.com/ssdomei232/goodBaby/drivers/github" + "github.com/ssdomei232/goodBaby/drivers/onebot" +) + +// InitValidatorRegistry 初始化验证器注册表并注册所有验证器 +func InitValidatorRegistry() *ValidatorRegistry { + registry := NewValidatorRegistry() + + // 注册所有规则验证器 + registry.Register(&bilibili.BilibiliDynamicRuleValidator{}) + registry.Register(&email.EmailRuleValidator{}) + registry.Register(&onebot.OneBotRuleValidator{}) + registry.Register(&dingtalk.DingTalkRuleValidator{}) + registry.Register(&github.GithubMakeRepositoryPublicRuleValidator{}) + + return registry +} diff --git a/main.go b/main.go index 03a5385..b0e21d0 100644 --- a/main.go +++ b/main.go @@ -36,14 +36,26 @@ func main() { authorized := v1.Group("/") authorized.Use(user.AuthMiddleware()) { - authorized.GET("/user/info", user.HandleGetUserInfo) - authorized.GET("/rules", rule.HandleGetAllRules) - authorized.POST("/rules", rule.HandleCreateRule) - authorized.DELETE("/rules/:ruleID", rule.HandleDeleteRule) - authorized.GET("/accounts", account.HandleGetAllAccounts) - authorized.POST("/accounts", account.HandleAddAccount) - authorized.GET("/accounts/:accountID/check", account.HandleCheckDeleteAccount) - authorized.DELETE("/accounts/:accountID", account.HandleDeleteAccount) + users := authorized.Group("/user") + { + users.GET("/info", user.HandleGetUserInfo) + } + + rules := authorized.Group("/rules") + { + rules.GET("/", rule.HandleGetAllRules) + rules.POST("/", rule.HandleCreateRule) + rules.PUT("/:ruleID", rule.HandleEditRule) + rules.DELETE("/:ruleID", rule.HandleDeleteRule) + } + + accounts := authorized.Group("/accounts") + { + accounts.GET("/", account.HandleGetAllAccounts) + accounts.POST("/", account.HandleAddAccount) + accounts.GET("/:accountID/check", account.HandleCheckDeleteAccount) + accounts.DELETE("/:accountID", account.HandleDeleteAccount) + } } r.Run(":8088")