yumi-golang/internal/router/game_king_routes.go
2026-07-18 15:32:58 +08:00

254 lines
8.6 KiB
Go

package router
import (
"net/http"
"strconv"
"strings"
"chatapp3-golang/internal/config"
"chatapp3-golang/internal/service/gameking"
"github.com/gin-gonic/gin"
)
// registerGameKingRoutes 注册 Yumi H5、运营后台和外部 cron 内部触发接口。
func registerGameKingRoutes(engine *gin.Engine, cfg config.Config, javaClient authGateway, service *gameking.Service) {
if service == nil {
return
}
h5 := engine.Group("/app/h5/game-king/yumi")
h5.Use(authMiddleware(javaClient))
h5.GET("/detail", func(c *gin.Context) {
resp, err := service.Detail(c.Request.Context(), mustAuthUser(c), parseGameKingID(c.Query("activityId")))
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
h5.GET("/me", func(c *gin.Context) {
resp, err := service.Me(c.Request.Context(), mustAuthUser(c), parseGameKingID(c.Query("activityId")))
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
h5.POST("/draw", func(c *gin.Context) {
var req gameking.DrawRequest
if err := c.ShouldBindJSON(&req); err != nil {
writeError(c, gameking.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
return
}
resp, err := service.Draw(c.Request.Context(), mustAuthUser(c), req)
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
h5.GET("/ranking", func(c *gin.Context) {
limit, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("limit", "30")))
resp, err := service.Ranking(c.Request.Context(), mustAuthUser(c), parseGameKingID(c.Query("activityId")), c.Query("rankingType"), c.Query("period"), limit)
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
h5.GET("/draw-records", func(c *gin.Context) {
limit, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("limit", "20")))
resp, err := service.DrawRecords(c.Request.Context(), mustAuthUser(c), parseGameKingID(c.Query("activityId")), limit)
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin := engine.Group("/resident-activity/game-king")
admin.Use(consoleAuthMiddleware(javaClient), consoleMenuMiddleware(javaClient, "ResidentGameKingActivity"))
admin.GET("/list", func(c *gin.Context) {
resp, err := service.ListActivities(c.Request.Context())
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin.GET("/detail/:id", func(c *gin.Context) {
resp, err := service.ManageDetail(c.Request.Context(), parseGameKingID(c.Param("id")))
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin.POST("/save", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:edit"), func(c *gin.Context) {
var req gameking.SaveActivityRequest
if err := c.ShouldBindJSON(&req); err != nil {
writeError(c, gameking.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
return
}
resp, err := service.SaveActivity(c.Request.Context(), req)
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin.PUT("/enable/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:enable"), func(c *gin.Context) {
raw, exists := c.GetQuery("enabled")
if !exists {
writeError(c, gameking.NewAppError(http.StatusBadRequest, "enabled_required", "enabled query is required"))
return
}
enabled, err := parseGameKingBool(raw, "enabled")
if err != nil {
writeError(c, err)
return
}
if err := service.EnableActivity(c.Request.Context(), parseGameKingID(c.Param("id")), enabled); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"success": true})
})
admin.GET("/prizes/:id", func(c *gin.Context) {
resp, err := service.ListPrizes(c.Request.Context(), parseGameKingID(c.Param("id")))
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin.PUT("/prizes/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:edit"), func(c *gin.Context) {
var req gameking.SavePrizesRequest
if err := c.ShouldBindJSON(&req); err != nil {
writeError(c, gameking.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
return
}
if err := service.SavePrizes(c.Request.Context(), parseGameKingID(c.Param("id")), req); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"success": true})
})
admin.GET("/rank-rewards/:id", func(c *gin.Context) {
resp, err := service.ListRankRewards(c.Request.Context(), parseGameKingID(c.Param("id")))
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin.PUT("/rank-rewards/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:edit"), func(c *gin.Context) {
var req gameking.SaveRankRewardsRequest
if err := c.ShouldBindJSON(&req); err != nil {
writeError(c, gameking.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
return
}
if err := service.SaveRankRewards(c.Request.Context(), parseGameKingID(c.Param("id")), req); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"success": true})
})
admin.GET("/draw-records/:id", func(c *gin.Context) {
limit, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("limit", "100")))
resp, err := service.ManageDrawRecords(c.Request.Context(), parseGameKingID(c.Param("id")), c.Query("deliveryStatus"), limit)
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin.POST("/draw/retry/:recordId", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:reconcile"), func(c *gin.Context) {
if err := service.RetryDraw(c.Request.Context(), parseGameKingID(c.Param("recordId"))); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"success": true})
})
admin.GET("/settlement-records/:id", func(c *gin.Context) {
resp, err := service.SettlementRecords(c.Request.Context(), parseGameKingID(c.Param("id")))
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
admin.POST("/settlement/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:settle"), func(c *gin.Context) {
if err := service.Settle(c.Request.Context(), parseGameKingID(c.Param("id"))); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"success": true})
})
admin.POST("/settlement/retry/:recordId", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:reconcile"), func(c *gin.Context) {
if err := service.RetrySettlement(c.Request.Context(), parseGameKingID(c.Param("recordId"))); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"success": true})
})
admin.POST("/delivery-item/resolve/:itemId", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:reconcile"), func(c *gin.Context) {
raw, exists := c.GetQuery("delivered")
if !exists {
writeError(c, gameking.NewAppError(http.StatusBadRequest, "delivered_required", "delivered query is required"))
return
}
delivered, err := parseGameKingBool(raw, "delivered")
if err != nil {
writeError(c, err)
return
}
if err := service.ResolveUnknownDeliveryItem(c.Request.Context(), parseGameKingID(c.Param("itemId")), delivered); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"success": true})
})
admin.POST("/backfill/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-game-king:backfill"), func(c *gin.Context) {
lastID := parseGameKingID(c.DefaultQuery("lastId", "0"))
limit, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("limit", "200")))
resp, err := service.Backfill(c.Request.Context(), parseGameKingID(c.Param("id")), lastID, limit)
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
internal := engine.Group("/internal/game-king")
// 结算入口会冻结榜单并产生真实奖励副作用,必须与 Yumi 礼物挑战保持相同的
// fail-closed 边界:服务端未配置密钥时直接拒绝,不能沿用历史内部接口的空密钥兼容行为。
internal.Use(requiredInternalSecretMiddleware(cfg.HTTP.InternalCallbackSecret))
internal.POST("/settle-due", func(c *gin.Context) {
resp, err := service.SettleDue(c.Request.Context())
if err != nil {
writeError(c, err)
return
}
writeOK(c, resp)
})
}
func parseGameKingID(value string) int64 {
parsed, _ := strconv.ParseInt(strings.TrimSpace(value), 10, 64)
return parsed
}
func parseGameKingBool(value, field string) (bool, error) {
switch strings.ToLower(strings.TrimSpace(value)) {
case "true", "1":
return true, nil
case "false", "0":
return false, nil
default:
// resolve delivered=false 会立即重发,因此不能把拼写错误或空值默认为 false。
return false, gameking.NewAppError(http.StatusBadRequest, field+"_invalid", field+" must be true, false, 1 or 0")
}
}