329 lines
6.8 KiB
Go
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)
|
|
}
|