refactor(api): extract repository layer and thin HTTP handlers

Introduce internal/repository for data access and cache-backed system
config reads. Move business logic into logics.go across admin push,
user, template, cache, system_config, and upload/handler packages.

Remove Gin from internal/util by relocating request-scoped helpers to
oauth/gin_context.go. Propagate request context for config lookups in
user flows. Slim model entities and delete model-level DB/cache helpers.

Wire handlers to logics/repository so targeted packages no longer call
db.DB directly. Update admin router tests to use ErrorHandlerMiddleware.
This commit is contained in:
ryan
2026-06-18 12:12:49 +08:00
parent e5b3a60f73
commit 1b2e083aec
77 changed files with 2370 additions and 1783 deletions
+32 -88
View File
@@ -3,15 +3,15 @@
package template
import ("errors"
import (
"errors"
"net/http"
"github.com/Rain-kl/Wavelet/internal/db"
"github.com/Rain-kl/Wavelet/internal/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"github.com/Rain-kl/Wavelet/internal/common/response")
"github.com/Rain-kl/Wavelet/internal/common/response"
)
// CreateTemplateRequest 创建模板请求
type CreateTemplateRequest struct {
@@ -32,6 +32,24 @@ type UpdateTemplateRequest struct {
Description string `json:"description" binding:"max=255"`
}
func abortTemplateLogicError(c *gin.Context, err error) bool {
if err == nil {
return false
}
if errors.Is(err, gorm.ErrRecordNotFound) {
response.AbortNotFound(c, TemplateNotFound)
return true
}
msg := err.Error()
switch msg {
case TemplateKeyExists, SystemTemplateCannotDelete:
response.AbortBadRequest(c, msg)
return true
}
response.AbortInternal(c, msg)
return true
}
// CreateTemplate 创建模板
// @Summary 创建模板
// @Description 创建一条新的自定义通知模板,模板标识符(Key)不可重复,需要管理员权限
@@ -53,33 +71,8 @@ func CreateTemplate(c *gin.Context) {
return
}
// 检查模板 Key 是否已存在
var existing model.Template
if err := db.DB(c.Request.Context()).Where("key = ?", req.Key).First(&existing).Error; err == nil {
response.AbortBadRequest(c, TemplateKeyExists)
return
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
response.AbortInternal(c, err.Error())
return
}
tmpl := model.Template{
Key: req.Key,
Name: req.Name,
Type: req.Type,
Subject: req.Subject,
Content: req.Content,
Description: req.Description,
IsSystem: false,
}
if err := tmpl.Validate(); err != nil {
response.AbortBadRequest(c, err.Error())
return
}
if err := db.DB(c.Request.Context()).Create(&tmpl).Error; err != nil {
response.AbortInternal(c, err.Error())
tmpl, err := createTemplate(c.Request.Context(), req)
if abortTemplateLogicError(c, err) {
return
}
@@ -98,8 +91,8 @@ func CreateTemplate(c *gin.Context) {
// @Failure 500 {object} response.Any "内部错误"
// @Router /api/v1/admin/templates [get]
func ListTemplates(c *gin.Context) {
var templates []model.Template
if err := db.DB(c.Request.Context()).Order("is_system DESC, created_at DESC").Find(&templates).Error; err != nil {
templates, err := listTemplates(c.Request.Context())
if err != nil {
response.AbortInternal(c, err.Error())
return
}
@@ -121,13 +114,8 @@ func ListTemplates(c *gin.Context) {
// @Failure 500 {object} response.Any "内部错误"
// @Router /api/v1/admin/templates/{key} [get]
func GetTemplate(c *gin.Context) {
var tmpl model.Template
if err := db.DB(c.Request.Context()).Where("key = ?", c.Param("key")).First(&tmpl).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
response.AbortNotFound(c, TemplateNotFound)
} else {
response.AbortInternal(c, err.Error())
}
tmpl, err := getTemplate(c.Request.Context(), c.Param("key"))
if abortTemplateLogicError(c, err) {
return
}
@@ -157,32 +145,8 @@ func UpdateTemplate(c *gin.Context) {
return
}
key := c.Param("key")
// 检查模板是否存在
var tmpl model.Template
if err := db.DB(c.Request.Context()).Where("key = ?", key).First(&tmpl).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
response.AbortNotFound(c, TemplateNotFound)
} else {
response.AbortInternal(c, err.Error())
}
return
}
tmpl.Name = req.Name
tmpl.Type = req.Type
tmpl.Subject = req.Subject
tmpl.Content = req.Content
tmpl.Description = req.Description
if err := tmpl.Validate(); err != nil {
response.AbortBadRequest(c, err.Error())
return
}
if err := db.DB(c.Request.Context()).Save(&tmpl).Error; err != nil {
response.AbortInternal(c, err.Error())
tmpl, err := updateTemplate(c.Request.Context(), c.Param("key"), req)
if abortTemplateLogicError(c, err) {
return
}
@@ -204,29 +168,9 @@ func UpdateTemplate(c *gin.Context) {
// @Failure 500 {object} response.Any "内部错误"
// @Router /api/v1/admin/templates/{key} [delete]
func DeleteTemplate(c *gin.Context) {
key := c.Param("key")
// 检查模板是否存在
var tmpl model.Template
if err := db.DB(c.Request.Context()).Where("key = ?", key).First(&tmpl).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
response.AbortNotFound(c, TemplateNotFound)
} else {
response.AbortInternal(c, err.Error())
}
return
}
// 限制系统模板删除
if tmpl.IsSystem {
response.AbortBadRequest(c, SystemTemplateCannotDelete)
return
}
if err := db.DB(c.Request.Context()).Delete(&tmpl).Error; err != nil {
response.AbortInternal(c, err.Error())
if err := deleteTemplate(c.Request.Context(), c.Param("key")); abortTemplateLogicError(c, err) {
return
}
c.JSON(http.StatusOK, response.OKNil())
}
}