296 lines
9.3 KiB
Go
296 lines
9.3 KiB
Go
package v1
|
|
|
|
import (
|
|
"github.com/labstack/echo/v4"
|
|
|
|
v1 "github.com/chaitin/panda-wiki/api/stat/v1"
|
|
"github.com/chaitin/panda-wiki/consts"
|
|
"github.com/chaitin/panda-wiki/domain"
|
|
"github.com/chaitin/panda-wiki/handler"
|
|
"github.com/chaitin/panda-wiki/log"
|
|
"github.com/chaitin/panda-wiki/middleware"
|
|
"github.com/chaitin/panda-wiki/usecase"
|
|
)
|
|
|
|
type StatHandler struct {
|
|
*handler.BaseHandler
|
|
usecase *usecase.StatUseCase
|
|
auth middleware.AuthMiddleware
|
|
logger *log.Logger
|
|
}
|
|
|
|
func NewStatHandler(baseHandler *handler.BaseHandler, echo *echo.Echo, usecase *usecase.StatUseCase, logger *log.Logger, auth middleware.AuthMiddleware) *StatHandler {
|
|
h := &StatHandler{
|
|
BaseHandler: baseHandler,
|
|
usecase: usecase,
|
|
auth: auth,
|
|
logger: logger.WithModule("handler.v1.stat"),
|
|
}
|
|
|
|
group := echo.Group("/api/v1/stat", h.auth.Authorize, auth.ValidateKBUserPerm(consts.UserKBPermissionDataOperate))
|
|
|
|
// 实时
|
|
group.GET("/instant_count", h.GetInstantCount) // instant count (30min, every 1min)
|
|
group.GET("/instant_pages", h.GetInstantPages) // instant pages (latest 10 pages)
|
|
|
|
// 周期统计
|
|
group.GET("/count", h.StatCount)
|
|
group.GET("/geo_count", h.StatGeoCountReq) // geo (24h)
|
|
group.GET("/conversation_distribution", h.StatConversationDistribution) // conversation (24h)
|
|
group.GET("/hot_pages", h.StatHotPages)
|
|
group.GET("/referer_hosts", h.StatRefererHosts)
|
|
group.GET("/browsers", h.StatBrowsers)
|
|
return h
|
|
}
|
|
|
|
// StatCount 全局统计
|
|
//
|
|
// @Summary 全局统计
|
|
// @Description 全局统计
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatCountReq true "para"
|
|
// @Success 200 {object} domain.PWResponse{data=v1.StatCountResp}
|
|
// @Router /api/v1/stat/count [get]
|
|
func (h *StatHandler) StatCount(c echo.Context) error {
|
|
var req v1.StatCountReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
if err := h.usecase.ValidateStatDay(req.Day, consts.GetLicenseEdition(c)); err != nil {
|
|
h.logger.Error("validate stat day failed")
|
|
return h.NewResponseWithErrCode(c, domain.ErrCodePermissionDenied)
|
|
}
|
|
|
|
count, err := h.usecase.GetStatCount(c.Request().Context(), req.KbID, req.Day)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get count failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, count)
|
|
}
|
|
|
|
// StatGeoCountReq 用户地理分布
|
|
//
|
|
// @Summary 用户地理分布
|
|
// @Description 用户地理分布
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatGeoCountReq true "para"
|
|
// @Success 200 {object} domain.Response
|
|
// @Router /api/v1/stat/geo_count [get]
|
|
func (h *StatHandler) StatGeoCountReq(c echo.Context) error {
|
|
var req v1.StatGeoCountReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
if err := h.usecase.ValidateStatDay(req.Day, consts.GetLicenseEdition(c)); err != nil {
|
|
h.logger.Error("validate stat day failed")
|
|
return h.NewResponseWithErrCode(c, domain.ErrCodePermissionDenied)
|
|
}
|
|
|
|
geoCount, err := h.usecase.GetGeoCount(c.Request().Context(), req.KbID, req.Day)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get geo count failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, geoCount)
|
|
}
|
|
|
|
// StatConversationDistribution
|
|
//
|
|
// @Summary 问答来源
|
|
// @Description 问答来源
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatConversationDistributionReq true "para"
|
|
// @Success 200 {object} domain.Response{data=[]v1.StatConversationDistributionResp}
|
|
// @Router /api/v1/stat/conversation_distribution [get]
|
|
func (h *StatHandler) StatConversationDistribution(c echo.Context) error {
|
|
var req v1.StatConversationDistributionReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
if err := h.usecase.ValidateStatDay(req.Day, consts.GetLicenseEdition(c)); err != nil {
|
|
h.logger.Error("validate stat day failed")
|
|
return h.NewResponseWithErrCode(c, domain.ErrCodePermissionDenied)
|
|
}
|
|
|
|
distribution, err := h.usecase.GetConversationDistribution(c.Request().Context(), req.KbID, req.Day)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get conversation distribution failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, distribution)
|
|
}
|
|
|
|
// StatHotPages 热门文档
|
|
//
|
|
// @Summary 热门文档
|
|
// @Description 热门文档
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatHotPagesReq true "para"
|
|
// @Success 200 {object} domain.Response{data=[]domain.HotPage}
|
|
// @Router /api/v1/stat/hot_pages [get]
|
|
func (h *StatHandler) StatHotPages(c echo.Context) error {
|
|
var req v1.StatHotPagesReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
if err := h.usecase.ValidateStatDay(req.Day, consts.GetLicenseEdition(c)); err != nil {
|
|
return h.NewResponseWithError(c, err.Error(), err)
|
|
}
|
|
|
|
hotPages, err := h.usecase.GetHotPages(c.Request().Context(), req.KbID, req.Day)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get hot pages failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, hotPages)
|
|
}
|
|
|
|
// StatRefererHosts 来源域名
|
|
//
|
|
// @Summary 来源域名
|
|
// @Description 来源域名
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatRefererHostsReq true "para"
|
|
// @Success 200 {object} domain.Response{data=[]domain.HotRefererHost}
|
|
// @Router /api/v1/stat/referer_hosts [get]
|
|
func (h *StatHandler) StatRefererHosts(c echo.Context) error {
|
|
var req v1.StatRefererHostsReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
if err := h.usecase.ValidateStatDay(req.Day, consts.GetLicenseEdition(c)); err != nil {
|
|
return h.NewResponseWithError(c, err.Error(), err)
|
|
}
|
|
|
|
refererHosts, err := h.usecase.GetHotRefererHosts(c.Request().Context(), req.KbID, req.Day)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get hot referer hosts failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, refererHosts)
|
|
}
|
|
|
|
// StatBrowsers 客户端统计
|
|
//
|
|
// @Summary 客户端统计
|
|
// @Description 客户端统计
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatBrowsersReq true "para"
|
|
// @Success 200 {object} domain.Response{data=domain.HotBrowser}
|
|
// @Router /api/v1/stat/browsers [get]
|
|
func (h *StatHandler) StatBrowsers(c echo.Context) error {
|
|
var req v1.StatBrowsersReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
if err := h.usecase.ValidateStatDay(req.Day, consts.GetLicenseEdition(c)); err != nil {
|
|
return h.NewResponseWithError(c, err.Error(), err)
|
|
}
|
|
|
|
hotBrowsers, err := h.usecase.GetHotBrowsers(c.Request().Context(), req.KbID, req.Day)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get hot browsers failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, hotBrowsers)
|
|
}
|
|
|
|
// GetInstantCount get instant count
|
|
//
|
|
// @Summary GetInstantCount
|
|
// @Description GetInstantCount
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatInstantCountReq true "para"
|
|
// @Success 200 {object} domain.Response{data=[]domain.InstantCountResp}
|
|
// @Router /api/v1/stat/instant_count [get]
|
|
func (h *StatHandler) GetInstantCount(c echo.Context) error {
|
|
var req v1.StatInstantCountReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
count, err := h.usecase.GetInstantCount(c.Request().Context(), req.KbID)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get instant count failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, count)
|
|
}
|
|
|
|
// GetInstantPages get instant pages
|
|
//
|
|
// @Summary GetInstantPages
|
|
// @Description GetInstantPages
|
|
// @Tags stat
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security bearerAuth
|
|
// @Param para query v1.StatInstantPagesReq true "para"
|
|
// @Success 200 {object} domain.Response{data=[]domain.InstantPageResp}
|
|
// @Router /api/v1/stat/instant_pages [get]
|
|
func (h *StatHandler) GetInstantPages(c echo.Context) error {
|
|
var req v1.StatInstantPagesReq
|
|
if err := c.Bind(&req); err != nil {
|
|
return h.NewResponseWithError(c, "invalid request parameters", err)
|
|
}
|
|
|
|
if err := c.Validate(&req); err != nil {
|
|
return h.NewResponseWithError(c, "validation failed", err)
|
|
}
|
|
|
|
pages, err := h.usecase.GetInstantPages(c.Request().Context(), req.KbID)
|
|
if err != nil {
|
|
return h.NewResponseWithError(c, "get instant pages failed", err)
|
|
}
|
|
return h.NewResponseWithData(c, pages)
|
|
}
|