package admin import ( "time" "github.com/gofiber/fiber/v2" "github.com/break/junhong_cmp_fiber/internal/model/dto" auditquery "github.com/break/junhong_cmp_fiber/internal/query/audit" integrationquery "github.com/break/junhong_cmp_fiber/internal/query/integration" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/response" ) // AuditHandler 提供平台基础审计调查只读接口。 type AuditHandler struct { auditQuery *auditquery.Query integrationQuery *integrationquery.Query } // NewAuditHandler 创建平台基础审计调查 Handler。 func NewAuditHandler(auditQuery *auditquery.Query, integrationQuery *integrationquery.Query) *AuditHandler { return &AuditHandler{auditQuery: auditQuery, integrationQuery: integrationQuery} } // ListEvents 查询平台全局审计事件。 // GET /api/admin/audit/events func (h *AuditHandler) ListEvents(c *fiber.Ctx) error { var request dto.AuditEventListRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.List(c.UserContext(), auditquery.EventFilter{ CreatedFrom: from, CreatedTo: to, Action: request.Action, Category: request.Category, ActorKind: request.ActorKind, ActorID: request.ActorID, Source: request.Source, Result: request.Result, Risk: request.Risk, ScopeType: request.ScopeType, ScopeID: request.ScopeID, ResourceType: request.ResourceType, ResourceID: request.ResourceID, ResourceKey: request.ResourceKey, RequestID: request.RequestID, CorrelationID: request.CorrelationID, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // GetEvent 查询单个稳定审计事件详情。 // GET /api/admin/audit/events/:event_id func (h *AuditHandler) GetEvent(c *fiber.Ctx) error { result, err := h.auditQuery.Get(c.UserContext(), c.Params("event_id")) if err != nil { return err } return response.Success(c, result) } // ListActorEvents 查询操作者行为时间线。 // GET /api/admin/audit/actors/:kind/:id/events func (h *AuditHandler) ListActorEvents(c *fiber.Ctx) error { var request dto.AuditActorEventsRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } request.Kind, request.ID = c.Params("kind"), c.Params("id") from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.ListActorEvents(c.UserContext(), auditquery.ActorEventFilter{ Kind: request.Kind, ID: request.ID, Action: request.Action, Result: request.Result, Risk: request.Risk, ResourceType: request.ResourceType, ResourceID: request.ResourceID, CreatedFrom: from, CreatedTo: to, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // SearchResources 按注册业务标识精确搜索资源。 // GET /api/admin/audit/resources/search func (h *AuditHandler) SearchResources(c *fiber.Ctx) error { var request dto.AuditResourceSearchRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.SearchResources(c.UserContext(), auditquery.ResourceSearchFilter{ ResourceType: request.ResourceType, Keyword: request.Keyword, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // ResourceTimeline 查询资源作为任意关系参与的通用事件时间线。 // GET /api/admin/audit/resources/:resource_type/:resource_id/timeline func (h *AuditHandler) ResourceTimeline(c *fiber.Ctx) error { var request dto.AuditResourceTimelineRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } request.ResourceType, request.ResourceID = c.Params("resource_type"), c.Params("resource_id") from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.ResourceTimeline(c.UserContext(), auditquery.ResourceTimelineFilter{ ResourceType: request.ResourceType, ResourceID: request.ResourceID, CreatedFrom: from, CreatedTo: to, Action: request.Action, Result: request.Result, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // RequestTimeline 查询指定 HTTP 请求关联的跨事实时间线。 // GET /api/admin/audit/requests/:request_id/timeline func (h *AuditHandler) RequestTimeline(c *fiber.Ctx) error { requestID := c.Params("request_id") if requestID == "" { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.RequestTimeline(c.UserContext(), requestID) if err != nil { return err } return response.Success(c, result) } // CorrelationTimeline 查询跨请求业务关联时间线。 // GET /api/admin/audit/correlations/:correlation_id/timeline func (h *AuditHandler) CorrelationTimeline(c *fiber.Ctx) error { correlationID := c.Params("correlation_id") if correlationID == "" { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.CorrelationTimeline(c.UserContext(), correlationID) if err != nil { return err } return response.Success(c, result) } // FinanceTimeline 查询资金审计与业务账本的组合时间线。 // GET /api/admin/audit/finance/timeline func (h *AuditHandler) FinanceTimeline(c *fiber.Ctx) error { var request dto.AuditFinanceTimelineRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.FinanceTimeline(c.UserContext(), auditquery.FinanceFilter{ ShopID: request.ShopID, WalletID: request.WalletID, OrderID: request.OrderID, OrderNo: request.OrderNo, PaymentID: request.PaymentID, PaymentNo: request.PaymentNo, RefundID: request.RefundID, RefundNo: request.RefundNo, RechargeID: request.RechargeID, RechargeNo: request.RechargeNo, ApprovalInstanceID: request.ApprovalInstanceID, ThirdPartyTradeNo: request.ThirdPartyTradeNo, ActorKind: request.ActorKind, ActorID: request.ActorID, CorrelationID: request.CorrelationID, CreatedFrom: from, CreatedTo: to, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // RiskOverview 查询固定风险信号总览。 // GET /api/admin/audit/risks/overview func (h *AuditHandler) RiskOverview(c *fiber.Ctx) error { var request dto.AuditRiskOverviewRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } filter, err := riskFilter(request.AuditRiskFilterRequest, 0, 0) if err != nil { return err } result, err := h.auditQuery.RiskOverview(c.UserContext(), filter) if err != nil { return err } return response.Success(c, result) } // RiskEvents 查询固定风险集合的事件明细。 // GET /api/admin/audit/risks/events func (h *AuditHandler) RiskEvents(c *fiber.Ctx) error { var request dto.AuditRiskEventsRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } filter, err := riskFilter(request.AuditRiskFilterRequest, request.Page, request.PageSize) if err != nil { return err } result, err := h.auditQuery.RiskEvents(c.UserContext(), filter) if err != nil { return err } return response.Success(c, result) } func riskFilter(request dto.AuditRiskFilterRequest, page, pageSize int) (auditquery.RiskFilter, error) { from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil { return auditquery.RiskFilter{}, errors.New(errors.CodeInvalidParam) } return auditquery.RiskFilter{ CreatedFrom: from, CreatedTo: to, Risk: request.Risk, Result: request.Result, Action: request.Action, Source: request.Source, Page: page, PageSize: pageSize, }, nil } // AgentResourceActivities 查询代理范围内的安全资源活动。 // GET /api/admin/agent/resource-activities/:resource_type/:identifier func (h *AuditHandler) AgentResourceActivities(c *fiber.Ctx) error { request, from, to, err := subjectActivityRequest(c) if err != nil { return err } result, err := h.auditQuery.AgentResourceActivities(c.UserContext(), auditquery.SubjectActivityFilter{ ResourceType: request.ResourceType, Identifier: request.Identifier, CreatedFrom: from, CreatedTo: to, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // EnterpriseResourceActivities 查询企业当前有效授权资产的安全资源活动。 // GET /api/admin/enterprise/resource-activities/:resource_type/:identifier func (h *AuditHandler) EnterpriseResourceActivities(c *fiber.Ctx) error { request, from, to, err := subjectActivityRequest(c) if err != nil { return err } result, err := h.auditQuery.EnterpriseResourceActivities(c.UserContext(), auditquery.SubjectActivityFilter{ ResourceType: request.ResourceType, Identifier: request.Identifier, CreatedFrom: from, CreatedTo: to, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } func subjectActivityRequest(c *fiber.Ctx) (dto.SubjectResourceActivityRequest, *time.Time, *time.Time, error) { var request dto.SubjectResourceActivityRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return request, nil, nil, errors.New(errors.CodeInvalidParam) } request.ResourceType = c.Params("resource_type") request.Identifier = c.Params("identifier") if request.ResourceType == "" || request.Identifier == "" { return request, nil, nil, errors.New(errors.CodeInvalidParam) } from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil { return request, nil, nil, errors.New(errors.CodeInvalidParam) } return request, from, to, nil } // IntegrationOverview 查询外部集成交互总览。 // GET /api/admin/audit/integrations/overview func (h *AuditHandler) IntegrationOverview(c *fiber.Ctx) error { var request dto.IntegrationOverviewRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } filter, err := integrationFilter(request.IntegrationFilterRequest) if err != nil { return err } result, err := h.integrationQuery.Overview(c.UserContext(), integrationquery.OverviewFilter{ ListFilter: filter, Bucket: request.Bucket, }) if err != nil { return err } return response.Success(c, result) } // ListIntegrations 查询外部集成交互列表。 // GET /api/admin/audit/integrations func (h *AuditHandler) ListIntegrations(c *fiber.Ctx) error { var request dto.IntegrationListRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } filter, err := integrationFilter(request.IntegrationFilterRequest) if err != nil { return err } filter.Page, filter.PageSize = request.Page, request.PageSize result, err := h.integrationQuery.List(c.UserContext(), filter) if err != nil { return err } return response.Success(c, result) } // GetIntegration 查询稳定外部集成记录详情。 // GET /api/admin/audit/integrations/:integration_id func (h *AuditHandler) GetIntegration(c *fiber.Ctx) error { result, err := h.integrationQuery.Get(c.UserContext(), c.Params("integration_id")) if err != nil { return err } return response.Success(c, result) } func integrationFilter(request dto.IntegrationFilterRequest) (integrationquery.ListFilter, error) { from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil { return integrationquery.ListFilter{}, errors.New(errors.CodeInvalidParam) } return integrationquery.ListFilter{ CreatedFrom: from, CreatedTo: to, IntegrationID: request.IntegrationID, Provider: request.Provider, Direction: request.Direction, Operation: request.Operation, Result: request.Result, ResultCategory: request.ResultCategory, ExternalID: request.ExternalID, ResourceType: request.ResourceType, ResourceID: request.ResourceID, ResourceKey: request.ResourceKey, TriggerSource: request.TriggerSource, TriggerScene: request.TriggerScene, TriggerSeries: request.TriggerSeries, StateChanged: request.StateChanged, HTTPStatus: request.HTTPStatus, ProviderCode: request.ProviderCode, RequestID: request.RequestID, CorrelationID: request.CorrelationID, }, nil } func auditTimeRange(fromValue, toValue string) (*time.Time, *time.Time, error) { from, err := optionalAuditTime(fromValue) if err != nil { return nil, nil, err } to, err := optionalAuditTime(toValue) if err != nil { return nil, nil, err } if from != nil && to != nil && !from.Before(*to) { return nil, nil, errors.New(errors.CodeInvalidParam) } return from, to, nil } func optionalAuditTime(value string) (*time.Time, error) { if value == "" { return nil, nil } parsed, err := time.Parse(time.RFC3339, value) if err != nil { return nil, err } return &parsed, nil } func invalidAuditPage(page, pageSize int) bool { return page < 0 || pageSize < 0 || pageSize > 100 }