更新配置代码

This commit is contained in:
GeekMaster
2025-08-26 15:33:32 +08:00
parent b6d81890cf
commit b3b1981264
22 changed files with 510 additions and 388 deletions

View File

@@ -94,15 +94,24 @@ func LoadSystemConfig(db *gorm.DB) *types.SystemConfig {
logger.Error("load license config error: ", err)
}
// 加载 GeekAPI 配置
var geekAPIConfig types.GeekAPIConfig
// 加载验证码配置
var captchaConfig types.CaptchaConfig
sysConfig.Id = 0
db.Where("name", types.ConfigKeyGeekAPI).First(&sysConfig)
err = utils.JsonDecode(sysConfig.Value, &geekAPIConfig)
db.Where("name", types.ConfigKeyCaptcha).First(&sysConfig)
err = utils.JsonDecode(sysConfig.Value, &captchaConfig)
if err != nil {
logger.Error("load geek service config error: ", err)
}
// 加载微信登录配置
var wxLoginConfig types.WxLoginConfig
sysConfig.Id = 0
db.Where("name", types.ConfigKeyWxLogin).First(&sysConfig)
err = utils.JsonDecode(sysConfig.Value, &wxLoginConfig)
if err != nil {
logger.Error("load wx login config error: ", err)
}
// 加载短信配置
var smsConfig types.SMSConfig
sysConfig.Id = 0
@@ -146,6 +155,7 @@ func LoadSystemConfig(db *gorm.DB) *types.SystemConfig {
OSS: ossConfig,
SMTP: smtpConfig,
Payment: paymentConfig,
GeekAPI: geekAPIConfig,
Captcha: captchaConfig,
WxLogin: wxLoginConfig,
}
}

View File

@@ -110,7 +110,8 @@ type SystemConfig struct {
OSS OSSConfig
SMS SMSConfig
SMTP SmtpConfig
GeekAPI GeekAPIConfig
Captcha CaptchaConfig
WxLogin WxLoginConfig
Jimeng JimengConfig
License License
}
@@ -121,7 +122,8 @@ const (
ConfigKeyNotice = "notice"
ConfigKeyAgreement = "agreement"
ConfigKeyPrivacy = "privacy"
ConfigKeyGeekAPI = "geekapi"
ConfigKeyCaptcha = "captcha"
ConfigKeyWxLogin = "wx_login"
ConfigKeyLicense = "license"
ConfigKeySms = "sms"
ConfigKeySmtp = "smtp"

View File

@@ -31,8 +31,3 @@ type WxLoginConfig struct {
NotifyURL string `json:"notify_url"` // 登录成功回调 URL
Enabled bool `json:"enabled"` // 是否启用微信登录
}
type GeekAPIConfig struct {
Captcha CaptchaConfig
WxLogin WxLoginConfig
}

View File

@@ -2,7 +2,7 @@ package types
type PaymentConfig struct {
Alipay AlipayConfig `json:"alipay"` // 支付宝支付渠道配置
Epay EpayConfig `json:"epay"` // GEEK 支付配置
Epay EpayConfig `json:"epay"` // 支付配置
WxPay WxPayConfig `json:"wxpay"` // 微信支付渠道配置
}

View File

@@ -8,109 +8,379 @@ package admin
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
import (
"encoding/json"
"errors"
"geekai/core"
"geekai/core/middleware"
"geekai/core/types"
"geekai/handler"
"geekai/service"
"geekai/store"
"geekai/service/oss"
"geekai/service/payment"
"geekai/service/sms"
"geekai/store/model"
"geekai/utils"
"geekai/utils/resp"
"github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/host"
"gorm.io/gorm"
)
type ConfigHandler struct {
handler.BaseHandler
levelDB *store.LevelDB
licenseService *service.LicenseService
configService *service.ConfigService
sysConfig *types.SystemConfig
alipayService *payment.AlipayService
wxpayService *payment.WxPayService
epayService *payment.EPayService
smsAliyun *sms.AliYunSmsService
smsBao *sms.BaoSmsService
smsManager *sms.SmsManager
localOss *oss.LocalStorage
qiniuOss *oss.QiNiuOss
aliyunOss *oss.AliYunOss
minioOss *oss.MiniOss
smtpService *service.SmtpService
captchaService *service.CaptchaService
wxLoginService *service.WxLoginService
}
func NewConfigHandler(app *core.AppServer, db *gorm.DB, levelDB *store.LevelDB, licenseService *service.LicenseService, configService *service.ConfigService) *ConfigHandler {
func NewConfigHandler(
app *core.AppServer,
db *gorm.DB,
licenseService *service.LicenseService,
sysConfig *types.SystemConfig,
alipayService *payment.AlipayService,
wxpayService *payment.WxPayService,
epayService *payment.EPayService,
smsAliyun *sms.AliYunSmsService,
smsBao *sms.BaoSmsService,
smsManager *sms.SmsManager,
localOss *oss.LocalStorage,
qiniuOss *oss.QiNiuOss,
aliyunOss *oss.AliYunOss,
minioOss *oss.MiniOss,
smtpService *service.SmtpService,
captchaService *service.CaptchaService,
wxLoginService *service.WxLoginService,
) *ConfigHandler {
return &ConfigHandler{
BaseHandler: handler.BaseHandler{App: app, DB: db},
levelDB: levelDB,
licenseService: licenseService,
configService: configService,
sysConfig: sysConfig,
alipayService: alipayService,
wxpayService: wxpayService,
epayService: epayService,
smsAliyun: smsAliyun,
smsBao: smsBao,
smsManager: smsManager,
localOss: localOss,
qiniuOss: qiniuOss,
aliyunOss: aliyunOss,
minioOss: minioOss,
smtpService: smtpService,
captchaService: captchaService,
wxLoginService: wxLoginService,
}
}
// RegisterRoutes 注册路由
func (h *ConfigHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/admin/config/")
group.GET("get", h.Get)
rg := h.App.Engine.Group("/api/admin/config")
// 需要管理员授权的接口
group.Use(middleware.AdminAuthMiddleware(h.App.Config.AdminSession.SecretKey, h.App.Redis))
// 需要管理员登录的接口
rg.Use(middleware.AdminAuthMiddleware(h.App.Config.AdminSession.SecretKey, h.App.Redis))
{
group.POST("update", h.Update)
group.POST("active", h.Active)
group.POST("test", h.Test)
group.GET("license", h.GetLicense)
rg.POST("update/base", h.UpdateBase)
rg.POST("update/notice", h.UpdateNotice)
rg.POST("update/captcha", h.UpdateCaptcha)
rg.POST("update/wx_login", h.UpdateWxLogin)
rg.POST("update/payment", h.UpdatePayment)
rg.POST("update/sms", h.UpdateSms)
rg.POST("update/oss", h.UpdateOss)
rg.POST("update/smtp", h.UpdateStmp)
rg.GET("get", h.Get)
rg.POST("license/active", h.Active)
rg.GET("license/get", h.GetLicense)
}
}
func (h *ConfigHandler) Update(c *gin.Context) {
var payload struct {
Key string `json:"key"`
Config json.RawMessage `json:"config"`
ConfigBak types.SystemConfig `json:"config_bak,omitempty"`
}
// UpdateBase 更新基础配置
func (h *ConfigHandler) UpdateBase(c *gin.Context) {
var data types.BaseConfig
if err := c.ShouldBindJSON(&payload); err != nil {
logger.Errorf("Update config failed: %v", err)
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
if payload.Key == "system" {
var sys types.SystemConfig
if err := json.Unmarshal(payload.Config, &sys); err != nil {
resp.ERROR(c, "系统配置解析失败: "+err.Error())
return
}
if (sys.Base.Copyright != payload.ConfigBak.Base.Copyright) && !h.licenseService.GetLicense().Configs.DeCopy {
resp.ERROR(c, "您无权修改版权信息,请先联系作者获取授权")
return
}
// 未授权的话不允许修改版权
license := h.licenseService.GetLicense()
if !license.IsActive && data.Copyright != h.sysConfig.Base.Copyright {
resp.ERROR(c, "未授权系统不允许修改版权信息")
return
}
// 使用统一配置服务写入与广播
if err := h.configService.Set(payload.Key, payload.Config); err != nil {
// 未授权的话不允许修改 Logo
if !license.IsActive && data.Logo != h.sysConfig.Base.Logo {
resp.ERROR(c, "未授权系统不允许修改 Logo")
return
}
err := h.Update(types.ConfigKeySystem, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
if payload.Key == "system" {
var sys types.SystemConfig
if err := json.Unmarshal(payload.Config, &sys); err == nil {
h.App.SysConfig = &sys
}
}
resp.SUCCESS(c)
h.sysConfig.Base = data
resp.SUCCESS(c, data)
}
// Get 获取指定的系统配置
func (h *ConfigHandler) Get(c *gin.Context) {
key := c.Query("key")
// UpdateNotice 更新公告配置
func (h *ConfigHandler) UpdateNotice(c *gin.Context) {
var data struct {
Content string `json:"content"`
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
err := h.Update(types.ConfigKeyNotice, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
resp.SUCCESS(c, data)
}
// UpdateCaptcha 更新行为验证码配置
func (h *ConfigHandler) UpdateCaptcha(c *gin.Context) {
var data types.CaptchaConfig
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
err := h.Update(types.ConfigKeyCaptcha, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
if data.Enabled {
h.captchaService.UpdateConfig(data)
}
h.sysConfig.Captcha = data
resp.SUCCESS(c, data)
}
// UpdatePayment 更新支付配置
func (h *ConfigHandler) UpdatePayment(c *gin.Context) {
var data types.PaymentConfig
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
var config model.Config
res := h.DB.Where("name", key).First(&config)
if res.Error != nil {
if errors.Is(res.Error, gorm.ErrRecordNotFound) {
resp.SUCCESS(c, map[string]interface{}{})
oldData := types.PaymentConfig{}
err := h.DB.Where("name", types.ConfigKeyPayment).First(&config).Error
if err == nil {
utils.JsonDecode(config.Value, &oldData)
}
err = h.Update(types.ConfigKeyPayment, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
// 如果启用状态发生改变,则需要更新支付服务配置
if data.WxPay.Enabled {
err = h.wxpayService.UpdateConfig(&data.WxPay)
if err != nil {
resp.ERROR(c, err.Error())
return
}
}
if data.Epay.Enabled {
h.epayService.UpdateConfig(&data.Epay)
}
if data.Alipay.Enabled {
err = h.alipayService.UpdateConfig(&data.Alipay)
if err != nil {
resp.ERROR(c, err.Error())
return
}
}
h.sysConfig.Payment = data
resp.SUCCESS(c, data)
}
// UpdateSms 更新短信配置
func (h *ConfigHandler) UpdateSms(c *gin.Context) {
var data types.SMSConfig
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
var config model.Config
oldData := types.SMSConfig{}
err := h.DB.Where("name", types.ConfigKeySms).First(&config).Error
if err == nil {
utils.JsonDecode(config.Value, &oldData)
}
err = h.Update(types.ConfigKeySms, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
// 更新服务配置
switch data.Active {
case sms.Ali:
err = h.smsAliyun.UpdateConfig(&data.Ali)
if err != nil {
resp.ERROR(c, err.Error())
return
}
case sms.Bao:
h.smsBao.UpdateConfig(&data.Bao)
}
h.smsManager.SetActive(data.Active)
resp.SUCCESS(c, data)
}
// UpdateOss 更新 Oss 配置
func (h *ConfigHandler) UpdateOss(c *gin.Context) {
var data types.OSSConfig
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
var config model.Config
oldData := types.OSSConfig{}
err := h.DB.Where("name", types.ConfigKeyOss).First(&config).Error
if err == nil {
utils.JsonDecode(config.Value, &oldData)
}
err = h.Update("oss", data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
// 更新服务配置
switch data.Active {
case oss.Local:
h.localOss.UpdateConfig(&data.Local)
case oss.QiNiu:
h.qiniuOss.UpdateConfig(&data.QiNiu)
case oss.AliYun:
err := h.aliyunOss.UpdateConfig(&data.AliYun)
if err != nil {
resp.ERROR(c, err.Error())
return
}
case oss.Minio:
err := h.minioOss.UpdateConfig(&data.Minio)
if err != nil {
resp.ERROR(c, err.Error())
return
}
}
h.sysConfig.OSS = data
resp.SUCCESS(c, data)
}
// UpdateStmp 更新 Stmp 配置
func (h *ConfigHandler) UpdateStmp(c *gin.Context) {
var data types.SmtpConfig
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
var config model.Config
oldData := types.SmtpConfig{}
err := h.DB.Where("name", types.ConfigKeySmtp).First(&config).Error
if err == nil {
utils.JsonDecode(config.Value, &oldData)
}
err = h.Update(types.ConfigKeySmtp, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
// 配置发生改变时更新服务配置
if !data.Equal(&oldData) {
h.smtpService.UpdateConfig(&data)
}
h.sysConfig.SMTP = data
resp.SUCCESS(c, data)
}
// UpdateWxLogin 更新微信登录配置
func (h *ConfigHandler) UpdateWxLogin(c *gin.Context) {
var data types.WxLoginConfig
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
err := h.Update(types.ConfigKeyWxLogin, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
if data.Enabled {
h.wxLoginService.UpdateConfig(data)
}
h.sysConfig.WxLogin = data
resp.SUCCESS(c, data)
}
// Update 更新系统配置
func (h *ConfigHandler) Update(name string, value any) error {
var config model.Config
err := h.DB.Where("name", name).First(&config).Error
if err != nil { // 不存在则创建
config.Name = name
config.Value = utils.JsonEncode(value)
return h.DB.Create(&config).Error
} else { // 存在则更新
config.Value = utils.JsonEncode(value)
return h.DB.Updates(&config).Error
}
}
// Get 获取指定名称的系统配置
func (h *ConfigHandler) Get(c *gin.Context) {
name := c.Query("key")
var config model.Config
res := h.DB.Where("name", name).First(&config)
if res.Error != nil {
resp.ERROR(c, res.Error.Error())
return
}
var value map[string]interface{}
var value map[string]any
err := utils.JsonDecode(config.Value, &value)
if err != nil {
resp.ERROR(c, err.Error())
@@ -120,23 +390,6 @@ func (h *ConfigHandler) Get(c *gin.Context) {
resp.SUCCESS(c, value)
}
// Test 配置测试(占位)
func (h *ConfigHandler) Test(c *gin.Context) {
var data struct {
Key string `json:"key"`
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
msg, err := h.configService.Test(data.Key)
if err != nil {
resp.ERROR(c, err.Error())
return
}
resp.SUCCESS(c, msg)
}
// Active 激活系统
func (h *ConfigHandler) Active(c *gin.Context) {
var data struct {
@@ -146,19 +399,21 @@ func (h *ConfigHandler) Active(c *gin.Context) {
resp.ERROR(c, types.InvalidArgs)
return
}
info, err := host.Info()
err := h.licenseService.ActiveLicense(data.License)
license := h.licenseService.GetLicense()
if err != nil {
resp.ERROR(c, err.Error())
return
}
err = h.licenseService.ActiveLicense(data.License, info.HostID)
if err != nil {
if err := h.Update(types.ConfigKeyLicense, license); err != nil {
resp.ERROR(c, err.Error())
return
}
// 更新系统配置
h.sysConfig.License = *license
resp.SUCCESS(c)
resp.SUCCESS(c, license.MachineId)
}
@@ -167,3 +422,5 @@ func (h *ConfigHandler) GetLicense(c *gin.Context) {
license := h.licenseService.GetLicense()
resp.SUCCESS(c, license)
}
//

View File

@@ -25,7 +25,7 @@ type CaptchaHandler struct {
}
func NewCaptchaHandler(app *core.AppServer, s *service.CaptchaService, sysConfig *types.SystemConfig) *CaptchaHandler {
return &CaptchaHandler{App: app, service: s, config: sysConfig.GeekAPI.Captcha}
return &CaptchaHandler{App: app, service: s, config: sysConfig.Captcha}
}
// RegisterRoutes 注册路由

View File

@@ -144,7 +144,6 @@ func main() {
fx.Provide(handler.NewPowerLogHandler),
fx.Provide(handler.NewJimengHandler),
fx.Provide(service.NewConfigService),
fx.Provide(service.NewMigrationService),
fx.Invoke(func(migrationService *service.MigrationService) {
migrationService.StartMigrate()
@@ -221,10 +220,10 @@ func main() {
fx.Provide(sms.NewBaoSmsService),
fx.Provide(sms.NewSmsManager),
fx.Provide(func(config *types.SystemConfig) *service.CaptchaService {
return service.NewCaptchaService(config.GeekAPI.Captcha)
return service.NewCaptchaService(config.Captcha)
}),
fx.Provide(func(config *types.SystemConfig, client *redis.Client) *service.WxLoginService {
return service.NewWxLoginService(config.GeekAPI.WxLogin, client)
return service.NewWxLoginService(config.WxLogin, client)
}),
// 支付服务

View File

@@ -27,6 +27,10 @@ func NewCaptchaService(captchaConfig types.CaptchaConfig) *CaptchaService {
}
}
func (s *CaptchaService) UpdateConfig(config types.CaptchaConfig) {
s.config = config
}
func (s *CaptchaService) Get() (interface{}, error) {
url := fmt.Sprintf("%s/api/captcha/get", types.GeekAPIURL)
var res types.BizVo

View File

@@ -1,146 +0,0 @@
package service
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Copyright 2023 The Geek-AI Authors. All rights reserved.
// Use of this source code is governed by a Apache-2.0 license
// that can be found in the LICENSE file.
// @Author yangjian102621@163.com
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
import (
"context"
"encoding/json"
"fmt"
"geekai/store/model"
"sync"
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
)
// ConfigService 统一的配置访问、缓存与通知服务
type ConfigService struct {
db *gorm.DB
rdb *redis.Client
mu sync.RWMutex
cache map[string]json.RawMessage
watchers map[string][]chan struct{}
}
func NewConfigService(db *gorm.DB, rdb *redis.Client) *ConfigService {
s := &ConfigService{
db: db,
rdb: rdb,
cache: make(map[string]json.RawMessage),
watchers: make(map[string][]chan struct{}),
}
go s.subscribe()
return s
}
// Get 以原始 JSON 获取配置(带本地缓存)
func (s *ConfigService) Get(key string) (json.RawMessage, error) {
s.mu.RLock()
if v, ok := s.cache[key]; ok {
s.mu.RUnlock()
return v, nil
}
s.mu.RUnlock()
var cfg model.Config
if err := s.db.Where("name", key).First(&cfg).Error; err != nil {
return nil, err
}
s.mu.Lock()
s.cache[key] = json.RawMessage(cfg.Value)
s.mu.Unlock()
return json.RawMessage(cfg.Value), nil
}
// GetInto 将配置解析进传入结构体
func (s *ConfigService) GetInto(key string, dest interface{}) error {
data, err := s.Get(key)
if err != nil {
return err
}
if len(data) == 0 {
return nil
}
return json.Unmarshal(data, dest)
}
// Set 设置配置并写入数据库,同时触发通知
func (s *ConfigService) Set(key string, config json.RawMessage) error {
value := string(config)
cfg := model.Config{Name: key, Value: value}
if err := s.db.Where("name", key).FirstOrCreate(&cfg, model.Config{Name: key}).Error; err != nil {
return err
}
if cfg.Id > 0 {
cfg.Value = value
if err := s.db.Updates(&cfg).Error; err != nil {
return err
}
}
s.mu.Lock()
s.cache[key] = json.RawMessage(value)
s.mu.Unlock()
s.notifyLocal(key)
s.publish(key)
return nil
}
// Watch 返回一个通道,当指定 key 发生变化时收到事件
func (s *ConfigService) Watch(key string) <-chan struct{} {
ch := make(chan struct{}, 1)
s.mu.Lock()
s.watchers[key] = append(s.watchers[key], ch)
s.mu.Unlock()
return ch
}
func (s *ConfigService) notifyLocal(key string) {
s.mu.RLock()
list := s.watchers[key]
s.mu.RUnlock()
for _, ch := range list {
select { // 非阻塞通知
case ch <- struct{}{}:
default:
}
}
}
// 通过 Redis 发布配置变更,便于多实例同步
func (s *ConfigService) publish(key string) {
if s.rdb == nil {
return
}
channel := "config:changed"
if err := s.rdb.Publish(context.Background(), channel, key).Err(); err != nil {
logger.Warnf("publish config change failed: %v", err)
}
}
func (s *ConfigService) subscribe() {
if s.rdb == nil {
return
}
channel := "config:changed"
sub := s.rdb.Subscribe(context.Background(), channel)
for msg := range sub.Channel() {
key := msg.Payload
logger.Infof("config changed: %s", key)
// 失效本地缓存并本地广播
s.mu.Lock()
delete(s.cache, key)
s.mu.Unlock()
s.notifyLocal(key)
}
}
// Test 预留统一测试入口,根据 key 执行连通性检查
func (s *ConfigService) Test(key string) (string, error) {
// TODO: 实现各配置类型的测试逻辑
return fmt.Sprintf("%s ok", key), nil
}

View File

@@ -53,7 +53,7 @@ type License struct {
}
// ActiveLicense 激活 License
func (s *LicenseService) ActiveLicense(license string, machineId string) error {
func (s *LicenseService) ActiveLicense(license string) error {
var res struct {
Code types.BizCode `json:"code"`
Message string `json:"message"`
@@ -61,7 +61,7 @@ func (s *LicenseService) ActiveLicense(license string, machineId string) error {
}
apiURL := fmt.Sprintf("%s/%s", types.GeekAPIURL, "api/license/active")
response, err := req.C().R().
SetBody(map[string]string{"license": license, "machine_id": machineId}).
SetBody(map[string]string{"license": license, "machine_id": s.machineId}).
SetSuccessResult(&res).Post(apiURL)
if err != nil {
return fmt.Errorf("发送激活请求失败: %v", err)
@@ -81,7 +81,7 @@ func (s *LicenseService) ActiveLicense(license string, machineId string) error {
s.license = &types.License{
Key: license,
MachineId: machineId,
MachineId: s.machineId,
Configs: res.Data.Configs,
ExpiredAt: res.Data.ExpiredAt,
IsActive: true,

View File

@@ -24,7 +24,7 @@ import (
"github.com/qiniu/go-sdk/v7/storage"
)
type QinNiuOss struct {
type QiNiuOss struct {
config *types.QiNiuOssConfig
mac *qbox.Mac
putPolicy storage.PutPolicy
@@ -33,8 +33,8 @@ type QinNiuOss struct {
proxyURL string
}
func NewQiNiuOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) *QinNiuOss {
s := &QinNiuOss{
func NewQiNiuOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) *QiNiuOss {
s := &QiNiuOss{
proxyURL: appConfig.ProxyURL,
}
if sysConfig.OSS.Active == QiNiu {
@@ -43,7 +43,7 @@ func NewQiNiuOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) *Qin
return s
}
func (s *QinNiuOss) UpdateConfig(config *types.QiNiuOssConfig) {
func (s *QiNiuOss) UpdateConfig(config *types.QiNiuOssConfig) {
zone, ok := storage.GetRegionByID(storage.RegionID(config.Zone))
if !ok {
zone = storage.ZoneHuanan
@@ -61,7 +61,7 @@ func (s *QinNiuOss) UpdateConfig(config *types.QiNiuOssConfig) {
s.uploader = formUploader
s.bucket = storage.NewBucketManager(mac, &storeConfig)
}
func (s QinNiuOss) PutFile(ctx *gin.Context, name string) (File, error) {
func (s QiNiuOss) PutFile(ctx *gin.Context, name string) (File, error) {
// 解析表单
file, err := ctx.FormFile(name)
if err != nil {
@@ -94,7 +94,7 @@ func (s QinNiuOss) PutFile(ctx *gin.Context, name string) (File, error) {
}
func (s QinNiuOss) PutUrlFile(fileURL string, ext string, useProxy bool) (string, error) {
func (s QiNiuOss) PutUrlFile(fileURL string, ext string, useProxy bool) (string, error) {
var fileData []byte
var err error
if useProxy {
@@ -123,7 +123,7 @@ func (s QinNiuOss) PutUrlFile(fileURL string, ext string, useProxy bool) (string
return fmt.Sprintf("%s/%s", s.config.Domain, ret.Key), nil
}
func (s QinNiuOss) PutBase64(base64Img string) (string, error) {
func (s QiNiuOss) PutBase64(base64Img string) (string, error) {
imageData, err := base64.StdEncoding.DecodeString(base64Img)
if err != nil {
return "", fmt.Errorf("error decoding base64:%v", err)
@@ -139,7 +139,7 @@ func (s QinNiuOss) PutBase64(base64Img string) (string, error) {
return fmt.Sprintf("%s/%s", s.config.Domain, ret.Key), nil
}
func (s QinNiuOss) Delete(fileURL string) error {
func (s QiNiuOss) Delete(fileURL string) error {
var objectKey string
if strings.HasPrefix(fileURL, "http") {
filename := filepath.Base(fileURL)
@@ -151,4 +151,4 @@ func (s QinNiuOss) Delete(fileURL string) error {
return s.bucket.Delete(s.config.Bucket, objectKey)
}
var _ Uploader = QinNiuOss{}
var _ Uploader = QiNiuOss{}

View File

@@ -20,11 +20,11 @@ type UploaderManager struct {
local *LocalStorage
aliyun *AliYunOss
mini *MiniOss
qiniu *QinNiuOss
qiniu *QiNiuOss
config *types.OSSConfig
}
func NewUploaderManager(sysConfig *types.SystemConfig, local *LocalStorage, aliyun *AliYunOss, mini *MiniOss, qiniu *QinNiuOss) (*UploaderManager, error) {
func NewUploaderManager(sysConfig *types.SystemConfig, local *LocalStorage, aliyun *AliYunOss, mini *MiniOss, qiniu *QiNiuOss) (*UploaderManager, error) {
if sysConfig.OSS.Active == "" {
sysConfig.OSS.Active = Local
}

View File

@@ -27,6 +27,10 @@ func NewSmtpService(appConfig *types.AppConfig) *SmtpService {
}
}
func (s *SmtpService) UpdateConfig(config *types.SmtpConfig) {
s.config = config
}
func (s *SmtpService) SendVerifyCode(to string, code int) error {
subject := fmt.Sprintf("%s 注册验证码", s.config.AppName)
body := fmt.Sprintf("【%s】您的验证码为 %d请不要告诉他人。如非本人操作请忽略此邮件。", s.config.AppName, code)