325 lines
10 KiB
Go
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
|
|
}
|