完善日志和审计链路

This commit is contained in:
yml
2026-06-02 21:40:23 +08:00
parent 1325c8fb89
commit 6dcea2d56c
20 changed files with 243 additions and 90 deletions
@@ -104,6 +104,7 @@ func auditMeta(c *gin.Context) AuditMeta {
return AuditMeta{
IP: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
RequestID: middleware.GetRequestID(c),
}
}
@@ -1,12 +1,11 @@
package adminuser
import (
"encoding/json"
"errors"
"hfb_sys/backend/internal/auditlog"
"hfb_sys/backend/internal/model"
"gorm.io/datatypes"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
@@ -15,10 +14,7 @@ type Repository struct {
db *gorm.DB
}
type AuditMeta struct {
IP string
UserAgent string
}
type AuditMeta = auditlog.Meta
func NewRepository(db *gorm.DB) *Repository {
return &Repository{db: db}
@@ -133,21 +129,15 @@ func (row userRow) toDTO() UserDTO {
}
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizID uint64, meta AuditMeta, detail map[string]any) error {
raw, err := json.Marshal(detail)
if err != nil {
return err
}
row := model.AuditLog{
return auditlog.Append(tx, auditlog.Entry{
ActorType: "admin",
ActorID: actorID,
Action: action,
BizType: "user",
BizID: &bizID,
IP: meta.IP,
UserAgent: meta.UserAgent,
Detail: datatypes.JSON(raw),
}
return tx.Create(&row).Error
Meta: meta,
Detail: detail,
})
}
func IsNotFound(err error) bool {
+3 -4
View File
@@ -3,6 +3,8 @@ package dispute
import (
"time"
"hfb_sys/backend/internal/auditlog"
"gorm.io/datatypes"
)
@@ -36,10 +38,7 @@ type ArbitrateRequest struct {
Remark string `json:"remark" binding:"required"`
Amount float64 `json:"amount"`
}
type AuditMeta struct {
IP string
UserAgent string
}
type AuditMeta = auditlog.Meta
type PaginatedResult struct {
Items []DisputeDTO `json:"items"`
+9 -4
View File
@@ -100,10 +100,7 @@ func (h *Handler) AdminArbitrate(c *gin.Context) {
response.BadRequest(c, "仲裁结果和备注不能为空")
return
}
item, err := h.service.Arbitrate(adminID, id, req, AuditMeta{
IP: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
})
item, err := h.service.Arbitrate(adminID, id, req, auditMeta(c))
if err != nil {
writeDisputeError(c, err)
return
@@ -111,6 +108,14 @@ func (h *Handler) AdminArbitrate(c *gin.Context) {
response.OK(c, item)
}
func auditMeta(c *gin.Context) AuditMeta {
return AuditMeta{
IP: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
RequestID: middleware.GetRequestID(c),
}
}
func currentAdminID(c *gin.Context) (uint64, bool) {
value, ok := c.Get(middleware.ContextAdminID)
if !ok {
+5 -10
View File
@@ -6,6 +6,7 @@ import (
"math"
"time"
"hfb_sys/backend/internal/auditlog"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/modules/notification"
"hfb_sys/backend/internal/modules/wallet"
@@ -470,21 +471,15 @@ func disputeType(input string, isCheckoutDispute bool) string {
}
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizType string, bizID uint64, meta AuditMeta, detail map[string]any) error {
raw, err := json.Marshal(detail)
if err != nil {
return err
}
row := model.AuditLog{
return auditlog.Append(tx, auditlog.Entry{
ActorType: "admin",
ActorID: actorID,
Action: action,
BizType: bizType,
BizID: &bizID,
IP: meta.IP,
UserAgent: meta.UserAgent,
Detail: datatypes.JSON(raw),
}
return tx.Create(&row).Error
Meta: meta,
Detail: detail,
})
}
func IsNotFound(err error) bool {
+3 -4
View File
@@ -4,6 +4,8 @@ import (
"encoding/json"
"strings"
"time"
"hfb_sys/backend/internal/auditlog"
)
type ListingDTO struct {
@@ -116,10 +118,7 @@ type AdminActionRequest struct {
Reason string `json:"reason" binding:"required"`
}
type AuditMeta struct {
IP string
UserAgent string
}
type AuditMeta = auditlog.Meta
type ExternalUploadRequest struct {
UploadTime int64 `json:"uploadTime"`
+9 -1
View File
@@ -174,7 +174,7 @@ func (h *Handler) adminAction(c *gin.Context, fn func(uint64, uint64, AdminActio
response.BadRequest(c, "操作原因不能为空")
return
}
item, err := fn(adminID, id, req, AuditMeta{IP: c.ClientIP(), UserAgent: c.GetHeader("User-Agent")})
item, err := fn(adminID, id, req, auditMeta(c))
if err != nil {
writeListingError(c, err)
return
@@ -182,6 +182,14 @@ func (h *Handler) adminAction(c *gin.Context, fn func(uint64, uint64, AdminActio
response.OK(c, item)
}
func auditMeta(c *gin.Context) AuditMeta {
return AuditMeta{
IP: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
RequestID: middleware.GetRequestID(c),
}
}
func (h *Handler) Approve(c *gin.Context) {
id, ok := parseID(c)
if !ok {
+5 -10
View File
@@ -10,6 +10,7 @@ import (
"strings"
"time"
"hfb_sys/backend/internal/auditlog"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/modules/notification"
@@ -1342,21 +1343,15 @@ func extractListingObjectKey(fileURL string) string {
}
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizType string, bizID uint64, meta AuditMeta, detail map[string]any) error {
raw, err := json.Marshal(detail)
if err != nil {
return err
}
row := model.AuditLog{
return auditlog.Append(tx, auditlog.Entry{
ActorType: "admin",
ActorID: actorID,
Action: action,
BizType: bizType,
BizID: &bizID,
IP: meta.IP,
UserAgent: meta.UserAgent,
Detail: datatypes.JSON(raw),
}
return tx.Create(&row).Error
Meta: meta,
Detail: detail,
})
}
func IsNotFound(err error) bool {
+3 -4
View File
@@ -3,6 +3,8 @@ package order
import (
"time"
"hfb_sys/backend/internal/auditlog"
"gorm.io/datatypes"
)
@@ -68,10 +70,7 @@ type AdminActionRequest struct {
Reason string `json:"reason" binding:"required"`
}
type AuditMeta struct {
IP string
UserAgent string
}
type AuditMeta = auditlog.Meta
type HandoffRecordDTO struct {
ID uint64 `json:"id"`
+9 -2
View File
@@ -110,13 +110,21 @@ func (h *Handler) adminAction(c *gin.Context, fn func(uint64, uint64, AdminActio
response.BadRequest(c, "操作原因不能为空")
return
}
if err := fn(adminID, id, req, AuditMeta{IP: c.ClientIP(), UserAgent: c.GetHeader("User-Agent")}); err != nil {
if err := fn(adminID, id, req, auditMeta(c)); err != nil {
writeOrderError(c, err)
return
}
response.OK(c, okData)
}
func auditMeta(c *gin.Context) AuditMeta {
return AuditMeta{
IP: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
RequestID: middleware.GetRequestID(c),
}
}
func (h *Handler) Detail(c *gin.Context) {
userID, ok := currentUserID(c)
if !ok {
@@ -375,7 +383,6 @@ func parseID(c *gin.Context) (uint64, bool) {
}
func writeOrderError(c *gin.Context, err error) {
println("DEBUG ORDER ERROR:", err.Error())
switch {
case errors.Is(err, ErrDependencyUnavailable):
response.ServiceUnavailable(c, "数据库未连接")
+5 -10
View File
@@ -9,6 +9,7 @@ import (
"strconv"
"time"
"hfb_sys/backend/internal/auditlog"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/modules/chat"
"hfb_sys/backend/internal/modules/notification"
@@ -1536,21 +1537,15 @@ func newOrderNo() (string, error) {
}
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizType string, bizID uint64, meta AuditMeta, detail map[string]any) error {
raw, err := json.Marshal(detail)
if err != nil {
return err
}
row := model.AuditLog{
return auditlog.Append(tx, auditlog.Entry{
ActorType: "admin",
ActorID: actorID,
Action: action,
BizType: bizType,
BizID: &bizID,
IP: meta.IP,
UserAgent: meta.UserAgent,
Detail: datatypes.JSON(raw),
}
return tx.Create(&row).Error
Meta: meta,
Detail: detail,
})
}
func IsNotFound(err error) bool {
@@ -75,10 +75,7 @@ func (h *Handler) Update(c *gin.Context) {
response.BadRequest(c, "配置值不能为空")
return
}
item, err := h.service.Update(adminID, key, req, AuditMeta{
IP: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
})
item, err := h.service.Update(adminID, key, req, auditMeta(c))
if err != nil {
writeConfigError(c, err)
return
@@ -86,6 +83,14 @@ func (h *Handler) Update(c *gin.Context) {
response.OK(c, item)
}
func auditMeta(c *gin.Context) AuditMeta {
return AuditMeta{
IP: c.ClientIP(),
UserAgent: c.GetHeader("User-Agent"),
RequestID: middleware.GetRequestID(c),
}
}
func currentAdminID(c *gin.Context) (uint64, bool) {
value, ok := c.Get(middleware.ContextAdminID)
if !ok {
@@ -5,9 +5,9 @@ import (
"errors"
"strings"
"hfb_sys/backend/internal/auditlog"
"hfb_sys/backend/internal/model"
"gorm.io/datatypes"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
@@ -16,10 +16,7 @@ type Repository struct {
db *gorm.DB
}
type AuditMeta struct {
IP string
UserAgent string
}
type AuditMeta = auditlog.Meta
type defaultConfig struct {
Key string
@@ -249,21 +246,15 @@ func isLegacyPublishOptionsValue(value string) bool {
}
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizID uint64, meta AuditMeta, detail map[string]any) error {
raw, err := json.Marshal(detail)
if err != nil {
return err
}
row := model.AuditLog{
return auditlog.Append(tx, auditlog.Entry{
ActorType: "admin",
ActorID: actorID,
Action: action,
BizType: "system_config",
BizID: &bizID,
IP: meta.IP,
UserAgent: meta.UserAgent,
Detail: datatypes.JSON(raw),
}
return tx.Create(&row).Error
Meta: meta,
Detail: detail,
})
}
func toDTO(row model.SystemConfig) ConfigDTO {
@@ -171,7 +171,6 @@ func ensureAccount(tx *gorm.DB, userID uint64) error {
}
func applyEntry(account *model.WalletAccount, entry Entry) (float64, error) {
println("DEBUG APPLY:", entry.UserID, "type:", entry.BalanceType, "dir:", entry.Direction, "amt:", fmt.Sprintf("%.2f", entry.Amount), "avail:", fmt.Sprintf("%.2f", account.AvailableBalance), "frozen:", fmt.Sprintf("%.2f", account.FrozenBalance))
entry.Amount = roundWalletMoney(entry.Amount)
account.AvailableBalance = roundWalletMoney(account.AvailableBalance)
account.FrozenBalance = roundWalletMoney(account.FrozenBalance)