40 lines
1.5 KiB
Go
40 lines
1.5 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"git.pcux.cn/xuans/Scert/backend/internal/repository"
|
|
)
|
|
|
|
// 失败审计覆盖会话、来源、参数及仓储拒绝;成功审计由仓储在成员变更事务内保证。
|
|
func (s *Server) projectMemberFailureAudit(action string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Next()
|
|
if c.Writer.Status() < 400 || s.projectMembers == nil {
|
|
return
|
|
}
|
|
projectID := c.Param("projectID")
|
|
if !validMemberIdentifier(projectID) {
|
|
projectID = ""
|
|
}
|
|
target := c.GetString(projectMemberTargetKey)
|
|
if target == "" && validMemberIdentifier(c.Param("userID")) {
|
|
target = c.Param("userID")
|
|
}
|
|
// 客户端取消请求不能取消已发生失败的审计;独立等待有上限,不无限阻塞关闭。
|
|
ctx, cancel := context.WithTimeout(context.WithoutCancel(c.Request.Context()), 3*time.Second)
|
|
defer cancel()
|
|
err := s.projectMembers.RecordProjectMemberFailure(ctx, repository.ProjectMemberFailure{
|
|
ActorID: c.GetString(authenticatedActorKey), ProjectID: projectID, UserID: target,
|
|
Action: action, StatusCode: c.Writer.Status(), RequestID: requestIDFromContext(c),
|
|
})
|
|
if err != nil && s.logger != nil {
|
|
// 原失败响应已经确定,不能补发成功;存储故障只记录稳定诊断,不打印请求体和数据库原始错误。
|
|
s.logger.Error("项目成员失败审计未保存", "request_id", requestIDFromContext(c), "status", c.Writer.Status())
|
|
}
|
|
}
|
|
}
|