admin_backend/sdk/abtest/handler/handler.go
hahwu ddae026231 ab test and notification
Co-authored-by: Copilot <copilot@github.com>
2026-04-24 17:23:55 +08:00

329 lines
6.8 KiB
Go

package handler
import (
"errors"
"net/http"
"strconv"
"backend/sdk/abtest/model"
"backend/sdk/abtest/service"
"github.com/gin-gonic/gin"
)
type Handler struct {
svc *service.Service
}
func New(svc *service.Service) *Handler {
return &Handler{svc: svc}
}
func ok(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, model.Response{Code: 0, Msg: "ok", Data: data})
}
func fail(c *gin.Context, httpCode int, msg string) {
c.JSON(httpCode, model.Response{Code: -1, Msg: msg})
}
func paramID(c *gin.Context, key string) (int64, bool) {
v, err := strconv.ParseInt(c.Param(key), 10, 64)
if err != nil {
fail(c, http.StatusBadRequest, "invalid "+key)
return 0, false
}
return v, true
}
func handleServiceErr(c *gin.Context, err error) {
switch {
case errors.Is(err, service.ErrExperimentNotFound), errors.Is(err, service.ErrVariantNotFound):
fail(c, http.StatusNotFound, err.Error())
case errors.Is(err, service.ErrNotRunning), errors.Is(err, service.ErrNoVariants):
fail(c, http.StatusBadRequest, err.Error())
default:
fail(c, http.StatusInternalServerError, err.Error())
}
}
// ==================== Experiment ====================
func (h *Handler) CreateExperiment(c *gin.Context) {
var req model.CreateExperimentReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
exp, err := h.svc.CreateExperiment(&req)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, exp)
}
func (h *Handler) GetExperiment(c *gin.Context) {
id, valid := paramID(c, "id")
if !valid {
return
}
exp, err := h.svc.GetExperiment(id)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, exp)
}
func (h *Handler) ListExperiments(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
var statusPtr *int
if s := c.Query("status"); s != "" {
v, err := strconv.Atoi(s)
if err != nil {
fail(c, http.StatusBadRequest, "invalid status")
return
}
statusPtr = &v
}
list, total, err := h.svc.ListExperiments(statusPtr, page, pageSize)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, gin.H{"list": list, "total": total, "page": page, "page_size": pageSize})
}
func (h *Handler) UpdateExperiment(c *gin.Context) {
id, valid := paramID(c, "id")
if !valid {
return
}
var req model.UpdateExperimentReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
exp, err := h.svc.UpdateExperiment(id, &req)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, exp)
}
func (h *Handler) DeleteExperiment(c *gin.Context) {
id, valid := paramID(c, "id")
if !valid {
return
}
if err := h.svc.DeleteExperiment(id); err != nil {
handleServiceErr(c, err)
return
}
ok(c, nil)
}
// ==================== Variant ====================
func (h *Handler) CreateVariant(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
var req model.CreateVariantReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
v, err := h.svc.CreateVariant(expID, &req)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, v)
}
func (h *Handler) ListVariants(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
list, err := h.svc.ListVariants(expID)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, list)
}
func (h *Handler) UpdateVariant(c *gin.Context) {
variantID, valid := paramID(c, "variantId")
if !valid {
return
}
var req model.UpdateVariantReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
v, err := h.svc.UpdateVariant(variantID, &req)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, v)
}
func (h *Handler) DeleteVariant(c *gin.Context) {
variantID, valid := paramID(c, "variantId")
if !valid {
return
}
if err := h.svc.DeleteVariant(variantID); err != nil {
handleServiceErr(c, err)
return
}
ok(c, nil)
}
// ==================== 用户分流 ====================
func (h *Handler) AssignUser(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
var req model.AssignUserReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
variant, err := h.svc.AssignUser(expID, req.UserID)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, variant)
}
// ==================== 事件追踪 ====================
func (h *Handler) TrackEvent(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
var req model.TrackEventReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
if err := h.svc.TrackEvent(expID, &req); err != nil {
handleServiceErr(c, err)
return
}
ok(c, nil)
}
// ==================== 实验结果 ====================
func (h *Handler) GetExperimentResult(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
result, err := h.svc.GetExperimentResult(expID)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, result)
}
// ==================== 批量查询玩家分组 ====================
func (h *Handler) GetUserGroups(c *gin.Context) {
userID := c.Param("userId")
if userID == "" {
fail(c, http.StatusBadRequest, "invalid userId")
return
}
groups, err := h.svc.GetUserGroups(userID)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, groups)
}
// ==================== 白名单管理 ====================
func (h *Handler) AddWhitelist(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
var req model.CreateWhitelistReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
w, err := h.svc.AddWhitelist(expID, &req)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, w)
}
func (h *Handler) BatchAddWhitelist(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
var req model.BatchCreateWhitelistReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
list, err := h.svc.BatchAddWhitelist(expID, &req)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, list)
}
func (h *Handler) RemoveWhitelist(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
userID := c.Param("userId")
if userID == "" {
fail(c, http.StatusBadRequest, "invalid userId")
return
}
if err := h.svc.RemoveWhitelist(expID, userID); err != nil {
handleServiceErr(c, err)
return
}
ok(c, nil)
}
func (h *Handler) ListWhitelist(c *gin.Context) {
expID, valid := paramID(c, "id")
if !valid {
return
}
list, err := h.svc.ListWhitelist(expID)
if err != nil {
handleServiceErr(c, err)
return
}
ok(c, list)
}