Initial commit: 网络验证平台
This commit is contained in:
@@ -0,0 +1,481 @@
|
||||
package developer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"verification-platform-backend/internal/database"
|
||||
"verification-platform-backend/internal/model"
|
||||
"verification-platform-backend/internal/service"
|
||||
"verification-platform-backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupEmailRoutes(r *gin.RouterGroup) {
|
||||
r.GET("/applications/:id/email-config", handleGetEmailConfig)
|
||||
r.PUT("/applications/:id/email-config", handleUpdateEmailConfig)
|
||||
r.POST("/applications/:id/email-config/test", handleTestEmailConfig)
|
||||
r.GET("/applications/:id/email-templates", handleGetEmailTemplates)
|
||||
r.GET("/applications/:id/email-templates/:template_id", handleGetEmailTemplate)
|
||||
r.POST("/applications/:id/email-templates", handleCreateEmailTemplate)
|
||||
r.PUT("/applications/:id/email-templates/:template_id", handleUpdateEmailTemplate)
|
||||
r.DELETE("/applications/:id/email-templates/:template_id", handleDeleteEmailTemplate)
|
||||
r.POST("/applications/:id/send-verify-code", handleSendVerifyCode)
|
||||
}
|
||||
|
||||
func handleGetEmailConfig(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var permission model.PackagePermission
|
||||
hasPermission := checkEmailPermission(userID.(uint), &permission)
|
||||
if !hasPermission {
|
||||
response.Error(c, 403, "您的套餐不支持邮件功能")
|
||||
return
|
||||
}
|
||||
|
||||
var smtpConfig model.AppSMTPConfig
|
||||
database.DB.Where("application_id = ?", app.ID).First(&smtpConfig)
|
||||
|
||||
result := gin.H{
|
||||
"enable_email_verify": app.EnableEmailVerify,
|
||||
"require_email_verify": app.RequireEmailVerify,
|
||||
"enable_password_reset": app.EnablePasswordReset,
|
||||
"permission": gin.H{
|
||||
"allow_email": permission.AllowEmail,
|
||||
},
|
||||
}
|
||||
|
||||
if smtpConfig.ID > 0 {
|
||||
result["smtp_config"] = gin.H{
|
||||
"id": smtpConfig.ID,
|
||||
"host": smtpConfig.Host,
|
||||
"port": smtpConfig.Port,
|
||||
"user": smtpConfig.User,
|
||||
"from_name": smtpConfig.FromName,
|
||||
"from_email": smtpConfig.FromEmail,
|
||||
"use_ssl": smtpConfig.UseSSL,
|
||||
"status": smtpConfig.Status,
|
||||
}
|
||||
} else {
|
||||
result["smtp_config"] = nil
|
||||
}
|
||||
|
||||
response.Success(c, result)
|
||||
}
|
||||
|
||||
func handleUpdateEmailConfig(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var permission model.PackagePermission
|
||||
hasPermission := checkEmailPermission(userID.(uint), &permission)
|
||||
if !hasPermission {
|
||||
response.Error(c, 403, "您的套餐不支持邮件功能")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
EnableEmailVerify bool `json:"enable_email_verify"`
|
||||
RequireEmailVerify bool `json:"require_email_verify"`
|
||||
EnablePasswordReset bool `json:"enable_password_reset"`
|
||||
SMTPConfig *struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
FromName string `json:"from_name"`
|
||||
FromEmail string `json:"from_email"`
|
||||
UseSSL bool `json:"use_ssl"`
|
||||
} `json:"smtp_config"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"enable_email_verify": req.EnableEmailVerify,
|
||||
"require_email_verify": req.RequireEmailVerify,
|
||||
"enable_password_reset": req.EnablePasswordReset,
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&app).Updates(updates).Error; err != nil {
|
||||
response.Error(c, 500, "更新失败")
|
||||
return
|
||||
}
|
||||
|
||||
if req.SMTPConfig != nil {
|
||||
var smtpConfig model.AppSMTPConfig
|
||||
database.DB.Where("application_id = ?", app.ID).First(&smtpConfig)
|
||||
|
||||
smtpConfig.ApplicationID = app.ID
|
||||
smtpConfig.Host = req.SMTPConfig.Host
|
||||
smtpConfig.Port = req.SMTPConfig.Port
|
||||
smtpConfig.User = req.SMTPConfig.User
|
||||
if req.SMTPConfig.Password != "" {
|
||||
smtpConfig.Password = req.SMTPConfig.Password
|
||||
}
|
||||
smtpConfig.FromName = req.SMTPConfig.FromName
|
||||
smtpConfig.FromEmail = req.SMTPConfig.FromEmail
|
||||
smtpConfig.UseSSL = req.SMTPConfig.UseSSL
|
||||
|
||||
if smtpConfig.ID > 0 {
|
||||
database.DB.Save(&smtpConfig)
|
||||
} else {
|
||||
database.DB.Create(&smtpConfig)
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
func handleTestEmailConfig(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, 400, "请输入有效的邮箱地址")
|
||||
return
|
||||
}
|
||||
|
||||
var smtpConfig model.AppSMTPConfig
|
||||
if err := database.DB.Where("application_id = ?", app.ID).First(&smtpConfig).Error; err != nil {
|
||||
response.Error(c, 400, "请先配置SMTP")
|
||||
return
|
||||
}
|
||||
|
||||
emailService := service.NewEmailService()
|
||||
config := service.EmailConfig{
|
||||
Host: smtpConfig.Host,
|
||||
Port: smtpConfig.Port,
|
||||
User: smtpConfig.User,
|
||||
Password: smtpConfig.Password,
|
||||
FromName: smtpConfig.FromName,
|
||||
FromEmail: smtpConfig.FromEmail,
|
||||
UseSSL: smtpConfig.UseSSL,
|
||||
}
|
||||
|
||||
if err := emailService.SendTestEmail(config, req.Email, app.Name); err != nil {
|
||||
response.Error(c, 500, fmt.Sprintf("发送失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "测试邮件已发送",
|
||||
})
|
||||
}
|
||||
|
||||
func handleGetEmailTemplates(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var permission model.PackagePermission
|
||||
hasPermission := checkEmailPermission(userID.(uint), &permission)
|
||||
if !hasPermission {
|
||||
response.Error(c, 403, "您的套餐不支持邮箱验证功能")
|
||||
return
|
||||
}
|
||||
|
||||
var templates []model.EmailTemplate
|
||||
database.DB.Where("application_id = ?", app.ID).Order("created_at DESC").Find(&templates)
|
||||
|
||||
response.Success(c, templates)
|
||||
}
|
||||
|
||||
func handleGetEmailTemplate(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
templateID := c.Param("template_id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var template model.EmailTemplate
|
||||
if err := database.DB.Where("id = ? AND application_id = ?", templateID, app.ID).First(&template).Error; err != nil {
|
||||
response.Error(c, 404, "模板不存在")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, template)
|
||||
}
|
||||
|
||||
func handleCreateEmailTemplate(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var permission model.PackagePermission
|
||||
hasPermission := checkEmailPermission(userID.(uint), &permission)
|
||||
if !hasPermission {
|
||||
response.Error(c, 403, "您的套餐不支持邮件功能")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Type string `json:"type" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Subject string `json:"subject" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
template := model.EmailTemplate{
|
||||
ApplicationID: app.ID,
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
Subject: req.Subject,
|
||||
Content: req.Content,
|
||||
Status: "active",
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&template).Error; err != nil {
|
||||
response.Error(c, 500, "创建失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, template)
|
||||
}
|
||||
|
||||
func handleUpdateEmailTemplate(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
templateID := c.Param("template_id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var permission model.PackagePermission
|
||||
hasPermission := checkEmailPermission(userID.(uint), &permission)
|
||||
if !hasPermission {
|
||||
response.Error(c, 403, "您的套餐不支持邮件功能")
|
||||
return
|
||||
}
|
||||
|
||||
var template model.EmailTemplate
|
||||
if err := database.DB.Where("id = ? AND application_id = ?", templateID, app.ID).First(&template).Error; err != nil {
|
||||
response.Error(c, 404, "模板不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Subject string `json:"subject"`
|
||||
Content string `json:"content"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{}
|
||||
if req.Type != "" {
|
||||
updates["type"] = req.Type
|
||||
}
|
||||
if req.Name != "" {
|
||||
updates["name"] = req.Name
|
||||
}
|
||||
if req.Subject != "" {
|
||||
updates["subject"] = req.Subject
|
||||
}
|
||||
if req.Content != "" {
|
||||
updates["content"] = req.Content
|
||||
}
|
||||
if req.Status != "" {
|
||||
updates["status"] = req.Status
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&template).Updates(updates).Error; err != nil {
|
||||
response.Error(c, 500, "更新失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, template)
|
||||
}
|
||||
|
||||
func handleDeleteEmailTemplate(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
templateID := c.Param("template_id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var permission model.PackagePermission
|
||||
hasPermission := checkEmailPermission(userID.(uint), &permission)
|
||||
if !hasPermission {
|
||||
response.Error(c, 403, "您的套餐不支持邮件功能")
|
||||
return
|
||||
}
|
||||
|
||||
if err := database.DB.Where("id = ? AND application_id = ?", templateID, app.ID).Delete(&model.EmailTemplate{}).Error; err != nil {
|
||||
response.Error(c, 500, "删除失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "删除成功",
|
||||
})
|
||||
}
|
||||
|
||||
func handleSendVerifyCode(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
appID := c.Param("id")
|
||||
|
||||
var app model.Application
|
||||
if err := database.DB.Where("id = ? AND user_id = ?", appID, userID).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Purpose string `json:"purpose"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, 400, "请输入有效的邮箱地址")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Purpose == "" {
|
||||
req.Purpose = "register"
|
||||
}
|
||||
|
||||
var smtpConfig model.AppSMTPConfig
|
||||
if err := database.DB.Where("application_id = ?", app.ID).First(&smtpConfig).Error; err != nil {
|
||||
response.Error(c, 400, "请先配置SMTP")
|
||||
return
|
||||
}
|
||||
|
||||
var template model.EmailTemplate
|
||||
database.DB.Where("application_id = ? AND type = ? AND status = ?", app.ID, req.Purpose, "active").
|
||||
Order("is_default DESC").First(&template)
|
||||
|
||||
code := generateVerifyCode()
|
||||
expireAt := time.Now().Add(15 * time.Minute)
|
||||
|
||||
verifyCode := model.EmailVerifyCode{
|
||||
ApplicationID: app.ID,
|
||||
Email: req.Email,
|
||||
Code: code,
|
||||
Purpose: req.Purpose,
|
||||
ExpiresAt: expireAt,
|
||||
}
|
||||
database.DB.Create(&verifyCode)
|
||||
|
||||
emailService := service.NewEmailService()
|
||||
config := service.EmailConfig{
|
||||
Host: smtpConfig.Host,
|
||||
Port: smtpConfig.Port,
|
||||
User: smtpConfig.User,
|
||||
Password: smtpConfig.Password,
|
||||
FromName: smtpConfig.FromName,
|
||||
FromEmail: smtpConfig.FromEmail,
|
||||
UseSSL: smtpConfig.UseSSL,
|
||||
}
|
||||
|
||||
subject := fmt.Sprintf("验证码 - %s", app.Name)
|
||||
content := fmt.Sprintf(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="UTF-8"></head>
|
||||
<body style="font-family: Arial, sans-serif; padding: 20px; background-color: #f5f5f5;">
|
||||
<div style="max-width: 600px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
<h2 style="color: #333; margin-bottom: 20px;">邮箱验证</h2>
|
||||
<p style="color: #666; line-height: 1.6;">您的验证码是:<strong style="font-size: 24px; color: #1890ff;">%s</strong></p>
|
||||
<p style="color: #999; font-size: 12px;">验证码有效期为15分钟,请尽快使用。</p>
|
||||
<hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">
|
||||
<p style="color: #999; font-size: 12px;">此邮件由 %s 系统自动发送,请勿回复。</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`, code, app.Name)
|
||||
|
||||
if template.ID > 0 {
|
||||
subject = template.Subject
|
||||
content = template.Content
|
||||
}
|
||||
|
||||
if err := emailService.SendEmail(config, req.Email, subject, content); err != nil {
|
||||
response.Error(c, 500, fmt.Sprintf("发送失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "验证码已发送",
|
||||
})
|
||||
}
|
||||
|
||||
func checkEmailPermission(userID uint, permission *model.PackagePermission) bool {
|
||||
var userPackage model.UserPackage
|
||||
if err := database.DB.Where("user_id = ? AND status = ?", userID, "active").
|
||||
Preload("Package").First(&userPackage).Error; err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if userPackage.ExpiredAt != nil && userPackage.ExpiredAt.Before(time.Now()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if err := database.DB.Where("package_id = ?", userPackage.PackageID).First(permission).Error; err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return permission.AllowEmail
|
||||
}
|
||||
|
||||
func generateVerifyCode() string {
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return fmt.Sprintf("%06d", r.Intn(1000000))
|
||||
}
|
||||
Reference in New Issue
Block a user