Files
likedream/internal/service/config/config_service.go
T
2026-03-26 15:19:43 +08:00

325 lines
10 KiB
Go

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 := "<h2>邮件配置测试成功</h2><p>如果您收到此邮件,说明当前邮件配置可以正常发信。</p>"
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
}