refactor(util): move response helper to common/response and session logic to oauth

- Relocated generic HTTP response helpers (Response, OK, Err, etc.) from internal/util/ to a dedicated internal/common/response/ package.
- Renamed ResponseAny to Any to resolve revive stuttering warnings.
- Moved session building options and cookie headers logic from internal/util/ to internal/apps/oauth/.
- Removed all direct imports of Gin/Sessions/HTTP frameworks from internal/util/ to keep general utilities 100% pure.
- Regenerated Swagger API documentation via make swagger.
- All tests and make code-check compile and pass with 0 issues.
This commit is contained in:
ryan
2026-06-15 16:38:44 +08:00
parent b3ed94342c
commit 953af7d8db
43 changed files with 1833 additions and 1853 deletions
+47 -48
View File
@@ -4,8 +4,7 @@
// Package push defines push notification HTTP routes.
package push
import (
"context"
import ("context"
"encoding/json"
"errors"
"fmt"
@@ -16,11 +15,11 @@ import (
"github.com/Rain-kl/Wavelet/internal/db"
"github.com/Rain-kl/Wavelet/internal/model"
"github.com/Rain-kl/Wavelet/internal/task"
"github.com/Rain-kl/Wavelet/internal/util"
"github.com/Rain-kl/Wavelet/pkg/push"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
"github.com/Rain-kl/Wavelet/internal/common/response")
// UpdateEventRequest 更新事件请求参数
type UpdateEventRequest struct {
@@ -70,17 +69,17 @@ func SyncEvents(ctx context.Context) error {
// @Tags admin-push
// @Produce json
// @Security SessionCookie
// @Success 200 {object} util.ResponseAny{data=[]model.PushEvent} "通知事件列表"
// @Success 200 {object} response.Any{data=[]model.PushEvent} "通知事件列表"
// @Router /api/v1/admin/push/events [get]
func ListEvents(c *gin.Context) {
ctx := c.Request.Context()
var events []model.PushEvent
if err := db.DB(ctx).Order("created_at DESC").Find(&events).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
c.JSON(http.StatusOK, util.OK(events))
c.JSON(http.StatusOK, response.OK(events))
}
// CreateEventRequest 创建事件请求参数
@@ -108,10 +107,10 @@ func findBuiltInEvent(key string) (EventMetadata, bool) {
// @Tags admin-push
// @Produce json
// @Security SessionCookie
// @Success 200 {object} util.ResponseAny{data=[]EventMetadata} "内置通知事件列表"
// @Success 200 {object} response.Any{data=[]EventMetadata} "内置通知事件列表"
// @Router /api/v1/admin/push/events/builtin [get]
func ListBuiltInEvents(c *gin.Context) {
c.JSON(http.StatusOK, util.OK(BuiltInEvents))
c.JSON(http.StatusOK, response.OK(BuiltInEvents))
}
func getEventInfo(req CreateEventRequest) (string, string, []byte, error) {
@@ -162,12 +161,12 @@ func getEventInfo(req CreateEventRequest) (string, string, []byte, error) {
// @Produce json
// @Security SessionCookie
// @Param request body CreateEventRequest true "创建参数"
// @Success 200 {object} util.ResponseAny{data=model.PushEvent} "创建成功"
// @Success 200 {object} response.Any{data=model.PushEvent} "创建成功"
// @Router /api/v1/admin/push/events [post]
func CreateEvent(c *gin.Context) {
var req CreateEventRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
return
}
@@ -175,18 +174,18 @@ func CreateEvent(c *gin.Context) {
eventKey, eventName, defaultTemplateBytes, err := getEventInfo(req)
if err != nil {
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
return
}
// 2. 检查是否已经创建过该事件的配置
var count int64
if err := db.DB(ctx).Model(&model.PushEvent{}).Where("event_key = ?", eventKey).Count(&count).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
if count > 0 {
c.JSON(http.StatusBadRequest, util.Err("this notification event is already configured"))
c.JSON(http.StatusBadRequest, response.Err("this notification event is already configured"))
return
}
@@ -197,7 +196,7 @@ func CreateEvent(c *gin.Context) {
} else {
var tempMap map[string]any
if err := json.Unmarshal([]byte(templateStr), &tempMap); err != nil {
c.JSON(http.StatusBadRequest, util.Err("custom template is not a valid JSON format"))
c.JSON(http.StatusBadRequest, response.Err("custom template is not a valid JSON format"))
return
}
}
@@ -223,16 +222,16 @@ func CreateEvent(c *gin.Context) {
}
if err := event.Validate(); err != nil {
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
return
}
if err := db.DB(ctx).Create(&event).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
c.JSON(http.StatusOK, util.OK(event))
c.JSON(http.StatusOK, response.OK(event))
}
// DeleteEvent 删除通知事件配置
@@ -242,13 +241,13 @@ func CreateEvent(c *gin.Context) {
// @Produce json
// @Security SessionCookie
// @Param id path int true "事件 ID"
// @Success 200 {object} util.ResponseAny{data=string} "删除成功"
// @Success 200 {object} response.Any{data=string} "删除成功"
// @Router /api/v1/admin/push/events/{id} [delete]
func DeleteEvent(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, util.Err("invalid event id"))
c.JSON(http.StatusBadRequest, response.Err("invalid event id"))
return
}
@@ -256,19 +255,19 @@ func DeleteEvent(c *gin.Context) {
var event model.PushEvent
if err := db.DB(ctx).First(&event, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, util.Err("notification event not found"))
c.JSON(http.StatusNotFound, response.Err("notification event not found"))
} else {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
}
return
}
if err := db.DB(ctx).Delete(&event).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
c.JSON(http.StatusOK, util.OKNil())
c.JSON(http.StatusOK, response.OKNil())
}
// UpdateEvent 更新通知事件
@@ -280,28 +279,28 @@ func DeleteEvent(c *gin.Context) {
// @Security SessionCookie
// @Param id path int true "事件 ID"
// @Param request body push.UpdateEventRequest true "更新参数"
// @Success 200 {object} util.ResponseAny{data=string} "修改成功"
// @Success 200 {object} response.Any{data=string} "修改成功"
// @Router /api/v1/admin/push/events/{id} [put]
func UpdateEvent(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, util.Err("invalid event id"))
c.JSON(http.StatusBadRequest, response.Err("invalid event id"))
return
}
var req UpdateEventRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
return
}
var event model.PushEvent
if err := db.DB(c.Request.Context()).First(&event, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, util.Err("notification event not found"))
c.JSON(http.StatusNotFound, response.Err("notification event not found"))
} else {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
}
return
}
@@ -312,16 +311,16 @@ func UpdateEvent(c *gin.Context) {
event.Enabled = req.Enabled
if err := event.Validate(); err != nil {
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
return
}
if err := db.DB(c.Request.Context()).Save(&event).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
c.JSON(http.StatusOK, util.OKNil())
c.JSON(http.StatusOK, response.OKNil())
}
// ToggleEvent 快捷切换通知事件启用状态
@@ -331,33 +330,33 @@ func UpdateEvent(c *gin.Context) {
// @Produce json
// @Security SessionCookie
// @Param id path int true "事件 ID"
// @Success 200 {object} util.ResponseAny{data=string} "切换成功"
// @Success 200 {object} response.Any{data=string} "切换成功"
// @Router /api/v1/admin/push/events/{id}/toggle [post]
func ToggleEvent(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, util.Err("invalid event id"))
c.JSON(http.StatusBadRequest, response.Err("invalid event id"))
return
}
var event model.PushEvent
if err := db.DB(c.Request.Context()).First(&event, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, util.Err("notification event not found"))
c.JSON(http.StatusNotFound, response.Err("notification event not found"))
} else {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
}
return
}
event.Enabled = !event.Enabled
if err := db.DB(c.Request.Context()).Model(&event).Update("enabled", event.Enabled).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
c.JSON(http.StatusOK, util.OK(event.Enabled))
c.JSON(http.StatusOK, response.OK(event.Enabled))
}
// pushHistoriesResponse 推送历史分页响应
@@ -378,7 +377,7 @@ type pushHistoriesResponse struct {
// @Param page_size query int false "分页大小"
// @Param event_key query string false "过滤事件名称"
// @Param status query string false "过滤发送状态"
// @Success 200 {object} util.ResponseAny{data=pushHistoriesResponse} "推送历史列表"
// @Success 200 {object} response.Any{data=pushHistoriesResponse} "推送历史列表"
// @Router /api/v1/admin/push/histories [get]
func ListHistories(c *gin.Context) {
pageStr := c.DefaultQuery("page", "1")
@@ -405,18 +404,18 @@ func ListHistories(c *gin.Context) {
var total int64
if err := query.Count(&total).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
var results []model.PushHistory
offset := (page - 1) * pageSize
if err := query.Offset(offset).Limit(pageSize).Find(&results).Error; err != nil {
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
c.JSON(http.StatusInternalServerError, response.Err(err.Error()))
return
}
c.JSON(http.StatusOK, util.OK(map[string]any{
c.JSON(http.StatusOK, response.OK(map[string]any{
"total": total,
"results": results,
}))
@@ -430,24 +429,24 @@ func ListHistories(c *gin.Context) {
// @Produce json
// @Security SessionCookie
// @Param request body push.TestPushRequest true "测试请求体"
// @Success 200 {object} util.ResponseAny{data=string} "测试成功"
// @Success 200 {object} response.Any{data=string} "测试成功"
// @Router /api/v1/admin/push/test [post]
func TestPush(c *gin.Context) {
var req TestPushRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
return
}
pusher, err := push.GetPusher(req.Config.Channel)
if err != nil {
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
return
}
// 校验配置
if err := pusher.ValidateConfig(req.Config); err != nil {
c.JSON(http.StatusBadRequest, util.Err(fmt.Sprintf("validation failed: %v", err)))
c.JSON(http.StatusBadRequest, response.Err(fmt.Sprintf("validation failed: %v", err)))
return
}
@@ -479,9 +478,9 @@ func TestPush(c *gin.Context) {
err = pusher.Send(c.Request.Context(), req.Config, req.Target, testBody, "", nil)
if err != nil {
c.JSON(http.StatusOK, util.Err(err.Error()))
c.JSON(http.StatusOK, response.Err(err.Error()))
return
}
c.JSON(http.StatusOK, util.OKNil())
c.JSON(http.StatusOK, response.OKNil())
}