feat(ops): ECR-007 行为分析与 ECR-008 内容运营后台
落地埋点 ingest/数据看板、首页宫格 CMS 与测评上下架;含账号引导、问答流式与免责声明去重,以及 review P1 审计同事务修复。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/yuxingu/digital-psychology/apps/api/internal/middleware"
|
||||
"github.com/yuxingu/digital-psychology/apps/api/internal/service/analytics"
|
||||
"github.com/yuxingu/digital-psychology/apps/api/pkg/response"
|
||||
)
|
||||
|
||||
// AnalyticsHandler serves POST /api/v1/analytics/events (DeviceAuth).
|
||||
type AnalyticsHandler struct {
|
||||
Svc *analytics.Service
|
||||
}
|
||||
|
||||
// Register mounts analytics routes on a DeviceAuth group.
|
||||
func (h *AnalyticsHandler) Register(api *gin.RouterGroup) {
|
||||
g := api.Group("/analytics")
|
||||
g.POST("/events", h.Ingest)
|
||||
}
|
||||
|
||||
func (h *AnalyticsHandler) Ingest(c *gin.Context) {
|
||||
userID, ok := middleware.UserIDFromContext(c)
|
||||
if !ok {
|
||||
response.Fail(c, http.StatusUnauthorized, 40100, "unauthorized")
|
||||
return
|
||||
}
|
||||
deviceKey := c.GetHeader(middleware.DeviceKeyHeader)
|
||||
if deviceKey == "" {
|
||||
response.Fail(c, http.StatusBadRequest, 40020, "device key required")
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
Items []analytics.EventIn `json:"items"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
response.Fail(c, http.StatusBadRequest, 40021, "invalid body")
|
||||
return
|
||||
}
|
||||
res, err := h.Svc.Ingest(c.Request.Context(), userID, deviceKey, body.Items)
|
||||
if err != nil {
|
||||
if errors.Is(err, analytics.ErrTooManyItems) {
|
||||
response.Fail(c, http.StatusBadRequest, 40022, "too many items")
|
||||
return
|
||||
}
|
||||
if errors.Is(err, analytics.ErrInvalidBatch) {
|
||||
response.Fail(c, http.StatusBadRequest, 40023, "invalid batch")
|
||||
return
|
||||
}
|
||||
response.Fail(c, http.StatusInternalServerError, 50020, "ingest failed")
|
||||
return
|
||||
}
|
||||
response.OK(c, res)
|
||||
}
|
||||
Reference in New Issue
Block a user