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

336 lines
9.8 KiB
Go

package router
import (
"net/http"
"strconv"
"strings"
"chatapp3-golang/internal/config"
"chatapp3-golang/internal/service/yumigiftchallenge"
"github.com/gin-gonic/gin"
)
const yumiGiftChallengeMenuAlias = "ResidentYumiGiftChallenge"
// registerYumiGiftChallengeRoutes 注册 Yumi H5 用户接口与 Console 配置、结算、核账接口。
func registerYumiGiftChallengeRoutes(engine *gin.Engine, cfg config.Config, javaClient authGateway, service *yumigiftchallenge.Service) {
if service == nil {
return
}
internal := engine.Group("/internal/yumi-gift-challenge")
// 结算会产生真实奖励副作用;密钥缺失也必须拒绝,不能沿用历史内部接口的空密钥兼容行为。
internal.Use(requiredInternalSecretMiddleware(cfg.HTTP.InternalCallbackSecret))
internal.POST("/settle-due", func(c *gin.Context) {
batch, err := parseOptionalInt(c.Query("batch"))
if err != nil {
writeError(c, err)
return
}
response, err := service.SettleDue(c.Request.Context(), batch)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
h5 := engine.Group("/app/h5/gift-challenge/yumi")
h5.Use(authMiddleware(javaClient))
h5.GET("/detail", func(c *gin.Context) {
activityID, err := parseOptionalInt64(c.Query("activityId"))
if err != nil {
writeError(c, err)
return
}
response, err := service.GetDetail(c.Request.Context(), mustAuthUser(c), activityID)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
h5.POST("/enter", func(c *gin.Context) {
var request yumigiftchallenge.EnterRequest
if err := c.ShouldBindJSON(&request); err != nil {
writeBadRequest(c, err)
return
}
response, err := service.Enter(c.Request.Context(), mustAuthUser(c), request)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
h5.GET("/ranking", func(c *gin.Context) {
activityID, err := parseOptionalInt64(c.Query("activityId"))
if err != nil {
writeError(c, err)
return
}
limit, err := parseOptionalInt(c.Query("limit"))
if err != nil {
writeError(c, err)
return
}
period := firstNonEmptyString(c.Query("periodType"), c.Query("period"))
response, err := service.GetRanking(c.Request.Context(), mustAuthUser(c), activityID, period, c.Query("statDate"), limit)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
h5.POST("/tasks/:taskCode/claim", func(c *gin.Context) {
var request yumigiftchallenge.ClaimRequest
if err := c.ShouldBindJSON(&request); err != nil {
writeBadRequest(c, err)
return
}
response, err := service.ClaimTask(c.Request.Context(), mustAuthUser(c), c.Param("taskCode"), request)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
admin := engine.Group("/resident-activity/yumi-gift-challenge")
admin.Use(consoleAuthMiddleware(javaClient))
read := admin.Group("")
read.Use(consoleMenuMiddleware(javaClient, yumiGiftChallengeMenuAlias))
read.GET("/list", func(c *gin.Context) {
page, pageErr := parseOptionalInt(c.Query("page"))
size, sizeErr := parseOptionalInt(c.Query("size"))
if pageErr != nil || sizeErr != nil {
writeError(c, firstParseError(pageErr, sizeErr))
return
}
response, err := service.ListActivities(c.Request.Context(), c.Query("sysOrigin"), page, size)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
read.GET("/detail/:id", func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
response, err := service.GetAdminDetail(c.Request.Context(), activityID)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
read.GET("/tasks/:id", func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
response, err := service.GetAdminDetail(c.Request.Context(), activityID)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response.Tasks)
})
read.GET("/rank-rewards/:id", func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
response, err := service.GetAdminDetail(c.Request.Context(), activityID)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response.RankRewards)
})
read.GET("/ranking/:id", func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
limit, err := parseOptionalInt(c.Query("limit"))
if err != nil {
writeError(c, err)
return
}
period := firstNonEmptyString(c.Query("periodType"), c.Query("period"))
response, err := service.GetAdminRanking(c.Request.Context(), activityID, period, c.Query("statDate"), limit)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
read.GET("/settlement-records/:id", func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
page, pageErr := parseOptionalInt(c.Query("page"))
size, sizeErr := parseOptionalInt(c.Query("size"))
if pageErr != nil || sizeErr != nil {
writeError(c, firstParseError(pageErr, sizeErr))
return
}
response, err := service.PageSettlementRecords(c.Request.Context(), activityID, c.Query("periodType"), c.Query("statDate"), c.Query("deliveryStatus"), page, size)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
admin.POST("/save", consolePermissionMiddleware(javaClient, "resident-activity:yumi-gift-challenge:edit"), func(c *gin.Context) {
var request yumigiftchallenge.SaveRequest
if err := c.ShouldBindJSON(&request); err != nil {
writeBadRequest(c, err)
return
}
response, err := service.SaveActivity(c.Request.Context(), request)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
admin.PUT("/enable/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-gift-challenge:enable"), func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
enabled, err := strconv.ParseBool(strings.TrimSpace(c.Query("enabled")))
if err != nil {
writeBadRequest(c, err)
return
}
if err := service.SetEnabled(c.Request.Context(), activityID, enabled); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"id": strconv.FormatInt(activityID, 10), "enabled": enabled})
})
admin.PUT("/tasks/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-gift-challenge:edit"), func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
var request yumigiftchallenge.TaskSaveRequest
if err := c.ShouldBindJSON(&request); err != nil {
writeBadRequest(c, err)
return
}
request.ActivityID = yumigiftchallenge.FlexibleInt64(activityID)
response, err := service.SaveTasks(c.Request.Context(), activityID, request)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
admin.PUT("/rank-rewards/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-gift-challenge:edit"), func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
var request yumigiftchallenge.RankRewardSaveRequest
if err := c.ShouldBindJSON(&request); err != nil {
writeBadRequest(c, err)
return
}
request.ActivityID = yumigiftchallenge.FlexibleInt64(activityID)
response, err := service.SaveRankRewards(c.Request.Context(), activityID, request)
if err != nil {
writeError(c, err)
return
}
writeOK(c, response)
})
admin.POST("/settlement/:id", consolePermissionMiddleware(javaClient, "resident-activity:yumi-gift-challenge:settle"), func(c *gin.Context) {
activityID, ok := requirePathInt64(c, "id")
if !ok {
return
}
var request yumigiftchallenge.SettlementRequest
if err := c.ShouldBindJSON(&request); err != nil {
writeBadRequest(c, err)
return
}
if err := service.Settle(c.Request.Context(), activityID, request); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"settled": true})
})
admin.POST("/delivery-item/resolve/:itemId", consolePermissionMiddleware(javaClient, "resident-activity:yumi-gift-challenge:reconcile"), func(c *gin.Context) {
itemID, ok := requirePathInt64(c, "itemId")
if !ok {
return
}
var request yumigiftchallenge.ResolveDeliveryRequest
if err := c.ShouldBindJSON(&request); err != nil {
writeBadRequest(c, err)
return
}
if err := service.ResolveUnknownDeliveryItem(c.Request.Context(), itemID, request.Delivered); err != nil {
writeError(c, err)
return
}
writeOK(c, gin.H{"id": strconv.FormatInt(itemID, 10), "delivered": request.Delivered})
})
}
func parseOptionalInt64(value string) (int64, error) {
value = strings.TrimSpace(value)
if value == "" {
return 0, nil
}
parsed, err := strconv.ParseInt(value, 10, 64)
if err != nil || parsed <= 0 {
return 0, yumigiftchallenge.NewAppError(http.StatusBadRequest, "invalid_id", "id must be a positive int64 string")
}
return parsed, nil
}
func parseOptionalInt(value string) (int, error) {
value = strings.TrimSpace(value)
if value == "" {
return 0, nil
}
parsed, err := strconv.Atoi(value)
if err != nil || parsed < 0 {
return 0, yumigiftchallenge.NewAppError(http.StatusBadRequest, "invalid_number", "query number must be a non-negative integer")
}
return parsed, nil
}
func requirePathInt64(c *gin.Context, name string) (int64, bool) {
value, err := parseOptionalInt64(c.Param(name))
if err != nil || value <= 0 {
if err == nil {
err = yumigiftchallenge.NewAppError(http.StatusBadRequest, "invalid_id", name+" must be a positive int64 string")
}
writeError(c, err)
return 0, false
}
return value, true
}
func firstParseError(values ...error) error {
for _, err := range values {
if err != nil {
return err
}
}
return yumigiftchallenge.NewAppError(http.StatusBadRequest, "bad_request", "invalid query")
}
func writeBadRequest(c *gin.Context, err error) {
writeError(c, yumigiftchallenge.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
}