package config import ( "context" "fmt" v1 "likedream-goframe/internal/api/v1" cst2 "likedream-goframe/internal/common/cst" "likedream-goframe/internal/common/db" errors2 "likedream-goframe/internal/common/errors" "likedream-goframe/internal/ent" "likedream-goframe/internal/ent/sysconfig" mailservice "likedream-goframe/internal/service/email" "likedream-goframe/internal/utils" ) type ConfigServiceV1 struct{} func NewV1() *ConfigServiceV1 { return &ConfigServiceV1{} } func (s *ConfigServiceV1) Get(ctx context.Context, req *v1.ConfigGetReq) *utils.Response[*ent.SysConfig] { config, err := db.Global.SysConfig.Query(). Where(sysconfig.KeyEQ(req.Key)). Only(ctx) if err != nil { if ent.IsNotFound(err) { utils.OkOrPanic(errors2.NewBusinessError(404, "配置不存在")) } utils.OkOrPanic(err) } return utils.SuccessWithData[*ent.SysConfig](config) } func (s *ConfigServiceV1) PublicGet(ctx context.Context, req *v1.ConfigPublicGetReq) *utils.Response[*ent.SysConfig] { allowedKeys := []string{"system.announcement", "system.allowRegister", "system.requireInviteCode"} allowed := false for _, key := range allowedKeys { if req.Key == key { allowed = true break } } if !allowed { utils.OkOrPanic(errors2.NewBusinessError(403, "该配置不允许公开访问")) } config, err := db.Global.SysConfig.Query(). Where(sysconfig.KeyEQ(req.Key)). Only(ctx) if err != nil { if ent.IsNotFound(err) { return utils.SuccessWithData[*ent.SysConfig](nil) } utils.OkOrPanic(err) } return utils.SuccessWithData[*ent.SysConfig](config) } func (s *ConfigServiceV1) List(ctx context.Context, req *v1.ConfigListReq) *utils.Response[[]*ent.SysConfig] { query := db.Global.SysConfig.Query(). Order(ent.Asc(sysconfig.FieldKey)) if req.Key != "" { query.Where(sysconfig.KeyContains(req.Key)) } total := query.CountX(ctx) var data []*ent.SysConfig if total > 0 { query.Limit(req.Size).Offset((req.Page - 1) * req.Size) data = query.AllX(ctx) } return utils.SuccessWithTotal[[]*ent.SysConfig](data, total) } func (s *ConfigServiceV1) Update(ctx context.Context, req *v1.ConfigUpdateReq) *utils.Response[any] { config, err := db.Global.SysConfig.Query(). Where(sysconfig.KeyEQ(req.Key)). Only(ctx) if err != nil { if ent.IsNotFound(err) { db.Global.SysConfig.Create(). SetKey(req.Key). SetValue(req.Value). SetDescription(req.Description). SetType("markdown"). SaveX(ctx) return utils.SuccessWithMsg("配置创建成功") } utils.OkOrPanic(err) } db.Global.SysConfig.UpdateOne(config). SetValue(req.Value). SetDescription(req.Description). ExecX(ctx) return utils.SuccessWithMsg("配置更新成功") } const ( PriceKeyCpdailyTask = "price.cpdaily_task" PriceKeyCpdailyLeave = "price.cpdaily_leave" PriceKeyCpdailyPhone = "price.cpdaily_phone" PriceKeyXxt = "price.xxt" PriceKeySmarteduSc = "price.smartedu_sc" ) func (s *ConfigServiceV1) GetPriceConfig(ctx context.Context, req *v1.PriceConfigGetReq) *utils.Response[*v1.PriceConfigResp] { resp := &v1.PriceConfigResp{ CpdailyTask: s.getConfigValue(ctx, PriceKeyCpdailyTask, "0.5"), CpdailyLeave: s.getConfigValue(ctx, PriceKeyCpdailyLeave, "4"), CpdailyPhone: s.getConfigValue(ctx, PriceKeyCpdailyPhone, "0.25"), Xxt: s.getConfigValue(ctx, PriceKeyXxt, "0"), SmarteduSc: s.getConfigValue(ctx, PriceKeySmarteduSc, "0"), } return utils.SuccessWithData[*v1.PriceConfigResp](resp) } func (s *ConfigServiceV1) getConfigValue(ctx context.Context, key, defaultValue string) string { config, err := db.Global.SysConfig.Query(). Where(sysconfig.KeyEQ(key)). Only(ctx) if err != nil { return defaultValue } return config.Value } func (s *ConfigServiceV1) UpdatePriceConfig(ctx context.Context, req *v1.PriceConfigUpdateReq) *utils.Response[any] { if req.CpdailyTask != "" { s.upsertConfig(ctx, PriceKeyCpdailyTask, req.CpdailyTask, "今日校园签到单价") } if req.CpdailyLeave != "" { s.upsertConfig(ctx, PriceKeyCpdailyLeave, req.CpdailyLeave, "今日校园请假单价") } if req.CpdailyPhone != "" { s.upsertConfig(ctx, PriceKeyCpdailyPhone, req.CpdailyPhone, "今日校园手机号单价") } if req.Xxt != "" { s.upsertConfig(ctx, PriceKeyXxt, req.Xxt, "学习通单价") } if req.SmarteduSc != "" { s.upsertConfig(ctx, PriceKeySmarteduSc, req.SmarteduSc, "四川智慧教育单价") } return utils.SuccessWithMsg("费率配置更新成功") } func (s *ConfigServiceV1) upsertConfig(ctx context.Context, key, value, description string) { config, err := db.Global.SysConfig.Query(). Where(sysconfig.KeyEQ(key)). Only(ctx) if err != nil { if ent.IsNotFound(err) { db.Global.SysConfig.Create(). SetKey(key). SetValue(value). SetDescription(description). SetType("number"). SaveX(ctx) return } utils.OkOrPanic(err) } db.Global.SysConfig.UpdateOne(config). SetValue(value). ExecX(ctx) } func (s *ConfigServiceV1) GetSmtpConfig(ctx context.Context, req *v1.SmtpConfigGetReq) *utils.Response[any] { keys := []string{ cst2.ConfigEmailAuthMode, cst2.ConfigEmailSMTPHost, cst2.ConfigEmailSMTPPort, cst2.ConfigEmailSMTPUsername, cst2.ConfigEmailSMTPPassword, cst2.ConfigEmailFromEmail, cst2.ConfigEmailFromName, cst2.ConfigEmailOAuthTenant, cst2.ConfigEmailOAuthClientID, cst2.ConfigEmailOAuthClientSecret, cst2.ConfigEmailOAuthRedirectURL, cst2.ConfigEmailOAuthRefreshToken, cst2.ConfigEmailOAuthScope, } result := make(map[string]string, len(keys)) for _, key := range keys { config, err := db.Global.SysConfig.Query().Where(sysconfig.KeyEQ(key)).Only(ctx) if err == nil { result[key] = config.Value } } cfg := mailservice.NormalizeConfig(mailservice.EmailConfig{ AuthMode: result[cst2.ConfigEmailAuthMode], SMTPHost: result[cst2.ConfigEmailSMTPHost], SMTPPort: atoiOrZero(result[cst2.ConfigEmailSMTPPort]), SMTPUsername: result[cst2.ConfigEmailSMTPUsername], SMTPPassword: result[cst2.ConfigEmailSMTPPassword], FromEmail: result[cst2.ConfigEmailFromEmail], FromName: result[cst2.ConfigEmailFromName], OAuthTenant: result[cst2.ConfigEmailOAuthTenant], OAuthClientID: result[cst2.ConfigEmailOAuthClientID], OAuthClientSecret: result[cst2.ConfigEmailOAuthClientSecret], OAuthRedirectURL: result[cst2.ConfigEmailOAuthRedirectURL], OAuthRefreshToken: result[cst2.ConfigEmailOAuthRefreshToken], OAuthScope: result[cst2.ConfigEmailOAuthScope], }) return utils.SuccessWithData[any](map[string]any{ "authMode": cfg.AuthMode, "smtpHost": cfg.SMTPHost, "smtpPort": cfg.SMTPPort, "smtpUsername": cfg.SMTPUsername, "smtpPassword": cfg.SMTPPassword, "fromEmail": cfg.FromEmail, "fromName": cfg.FromName, "oauthTenant": cfg.OAuthTenant, "oauthClientId": cfg.OAuthClientID, "oauthClientSecret": cfg.OAuthClientSecret, "oauthRedirectUrl": cfg.OAuthRedirectURL, "oauthRefreshToken": cfg.OAuthRefreshToken, "oauthScope": cfg.OAuthScope, }) } func (s *ConfigServiceV1) UpdateSmtpConfig(ctx context.Context, req *v1.SmtpConfigUpdateReq) *utils.Response[any] { cfg := mailservice.NormalizeConfig(mailservice.EmailConfig{ AuthMode: req.AuthMode, SMTPHost: req.SmtpHost, SMTPPort: req.SmtpPort, SMTPUsername: req.SmtpUsername, SMTPPassword: req.SmtpPassword, FromEmail: req.FromEmail, FromName: req.FromName, OAuthTenant: req.OAuthTenant, OAuthClientID: req.OAuthClientID, OAuthClientSecret: req.OAuthClientSecret, OAuthRedirectURL: req.OAuthRedirectURL, OAuthRefreshToken: req.OAuthRefreshToken, OAuthScope: req.OAuthScope, }) if err := mailservice.NewV1().ValidateConfig(cfg); err != nil { utils.OkOrPanic(errors2.NewBusinessError(400, err.Error())) } configs := map[string]string{ cst2.ConfigEmailAuthMode: cfg.AuthMode, cst2.ConfigEmailSMTPHost: cfg.SMTPHost, cst2.ConfigEmailSMTPPort: fmt.Sprintf("%d", cfg.SMTPPort), cst2.ConfigEmailSMTPUsername: cfg.SMTPUsername, cst2.ConfigEmailSMTPPassword: cfg.SMTPPassword, cst2.ConfigEmailFromEmail: cfg.FromEmail, cst2.ConfigEmailFromName: cfg.FromName, cst2.ConfigEmailOAuthTenant: cfg.OAuthTenant, cst2.ConfigEmailOAuthClientID: cfg.OAuthClientID, cst2.ConfigEmailOAuthClientSecret: cfg.OAuthClientSecret, cst2.ConfigEmailOAuthRedirectURL: cfg.OAuthRedirectURL, cst2.ConfigEmailOAuthRefreshToken: cfg.OAuthRefreshToken, cst2.ConfigEmailOAuthScope: cfg.OAuthScope, } for key, value := range configs { exists, _ := db.Global.SysConfig.Query().Where(sysconfig.KeyEQ(key)).Exist(ctx) if exists { db.Global.SysConfig.Update().Where(sysconfig.KeyEQ(key)).SetValue(value).ExecX(ctx) } else { db.Global.SysConfig.Create(). SetKey(key). SetValue(value). SetDescription("邮件配置"). ExecX(ctx) } } return utils.SuccessWithMsg("邮件配置保存成功") } func (s *ConfigServiceV1) TestSmtp(ctx context.Context, req *v1.SmtpTestReq) *utils.Response[any] { emailService := mailservice.NewV1() cfg := emailService.GetConfig() if err := emailService.ValidateConfig(cfg); err != nil { utils.OkOrPanic(errors2.NewBusinessError(400, err.Error())) } subject := "邮件配置测试" body := "
如果您收到此邮件,说明当前邮件配置可以正常发信。
" if err := emailService.SendMessageNow(ctx, cfg, req.ToEmail, subject, body); err != nil { utils.OkOrPanic(err) } return utils.SuccessWithMsg("测试邮件发送成功") } func (s *ConfigServiceV1) GetOutlookOAuthAuthorizeURL(ctx context.Context, req *v1.OutlookOAuthAuthorizeURLReq) *utils.Response[*v1.OutlookOAuthAuthorizeURLResp] { cfg := mailservice.NormalizeConfig(mailservice.EmailConfig{ AuthMode: mailservice.AuthModeOutlookOAuth2, FromEmail: req.FromEmail, FromName: "Microsoft Graph OAuth2", OAuthTenant: req.OAuthTenant, OAuthClientID: req.OAuthClientID, OAuthClientSecret: req.OAuthClientSecret, OAuthScope: req.OAuthScope, }) resp, err := mailservice.NewV1().BuildOutlookAuthorizeURL(cfg, req.CallbackBaseURL, req.FrontendOrigin) if err != nil { utils.OkOrPanic(errors2.NewBusinessError(400, err.Error())) } return utils.SuccessWithData(resp) } func atoiOrZero(value string) int { if value == "" { return 0 } var result int _, _ = fmt.Sscanf(value, "%d", &result) return result }