You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/api/sms/utils.go

91 lines
2.2 KiB
Go

2 months ago
//
// utils.go
// Copyright (C) 2025 veypi <i@veypi.com>
//
// Distributed under terms of the MIT license.
//
package sms
import (
"fmt"
"time"
"github.com/veypi/OneAuth/cfg"
"github.com/veypi/OneAuth/models"
"gorm.io/gorm"
)
// checkDailyLimit 检查每日发送次数限制
func CheckDailyLimit(phone, region string) error {
today := time.Now().Truncate(24 * time.Hour)
tomorrow := today.Add(24 * time.Hour)
var count int64
err := cfg.DB().Model(&models.SMSCode{}).
Where("phone = ? AND region = ? AND created_at >= ? AND created_at < ?",
phone, region, today, tomorrow).
Count(&count).Error
if err != nil {
return fmt.Errorf("failed to check daily limit: %w", err)
}
if count >= int64(cfg.Config.SMS.Global.MaxDailyCount) {
return fmt.Errorf("daily sms limit exceeded")
}
return nil
}
// checkSendInterval 检查发送间隔
func CheckSendInterval(phone, region, purpose string) error {
var lastCode models.SMSCode
err := cfg.DB().Where("phone = ? AND region = ? AND purpose = ?", phone, region, purpose).
Order("created_at DESC").
First(&lastCode).Error
if err != nil && err != gorm.ErrRecordNotFound {
return fmt.Errorf("failed to check send interval: %w", err)
}
if err == nil {
timeSinceLastSend := time.Since(lastCode.CreatedAt)
if timeSinceLastSend < cfg.Config.SMS.Global.SendInterval {
remaining := cfg.Config.SMS.Global.SendInterval - timeSinceLastSend
return fmt.Errorf("please wait %d seconds before sending again", int(remaining.Seconds()))
}
}
return nil
}
// logSMS 记录短信发送日志
func LogSMS(phone, region, provider, messageID string, err error) {
log := &models.SMSLog{
Phone: phone,
Region: region,
Provider: provider,
MessageID: messageID,
Status: "ok",
}
if err != nil {
log.Status = "failed"
log.Error = err.Error()
}
cfg.DB().Create(log)
}
// CleanupExpiredCodes 清理过期的验证码
func CleanupExpiredCodes() error {
result := cfg.DB().Model(&models.SMSCode{}).
Where("status = ? AND expires_at < ?", models.CodeStatusPending, time.Now()).
Update("status", models.CodeStatusExpired)
if result.Error != nil {
return fmt.Errorf("failed to cleanup expired codes: %w", result.Error)
}
return nil
}