From 4e35dff05c52f7fa2845de194e7b5b8ed8d15ca9 Mon Sep 17 00:00:00 2001 From: Rogee Date: Tue, 13 Jan 2026 11:21:35 +0800 Subject: [PATCH] fix: pass operator id to audit logs --- backend/app/services/super.go | 16 +++++++++++----- backend/app/services/super_test.go | 8 +++++--- docs/todo_list.md | 1 + 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/backend/app/services/super.go b/backend/app/services/super.go index 8b3a0b9..08a4d77 100644 --- a/backend/app/services/super.go +++ b/backend/app/services/super.go @@ -1780,7 +1780,10 @@ func (s *super) ListWithdrawals(ctx context.Context, filter *super_dto.SuperOrde }, nil } -func (s *super) ApproveWithdrawal(ctx context.Context, id int64) error { +func (s *super) ApproveWithdrawal(ctx context.Context, operatorID, id int64) error { + if operatorID == 0 { + return errorx.ErrUnauthorized.WithMsg("缺少操作者信息") + } o, err := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(id)).First() if err != nil { return errorx.ErrRecordNotFound @@ -1796,7 +1799,7 @@ func (s *super) ApproveWithdrawal(ctx context.Context, id int64) error { UpdatedAt: time.Now(), }) if err == nil && Audit != nil { - Audit.Log(ctx, 0, "approve_withdrawal", cast.ToString(id), "Approved withdrawal") + Audit.Log(ctx, operatorID, "approve_withdrawal", cast.ToString(id), "Approved withdrawal") } return err } @@ -1956,7 +1959,10 @@ func (s *super) formatTime(t time.Time) string { return t.Format(time.RFC3339) } -func (s *super) RejectWithdrawal(ctx context.Context, id int64, reason string) error { +func (s *super) RejectWithdrawal(ctx context.Context, operatorID, id int64, reason string) error { + if operatorID == 0 { + return errorx.ErrUnauthorized.WithMsg("缺少操作者信息") + } err := models.Q.Transaction(func(tx *models.Query) error { o, err := tx.Order.WithContext(ctx).Where(tx.Order.ID.Eq(id)).First() if err != nil { @@ -1990,7 +1996,7 @@ func (s *super) RejectWithdrawal(ctx context.Context, id int64, reason string) e Type: consts.TenantLedgerTypeAdjustment, Amount: o.AmountPaid, Remark: "提现拒绝返还: " + reason, - OperatorUserID: 0, // System/Admin + OperatorUserID: operatorID, IdempotencyKey: uuid.NewString(), } if err := tx.TenantLedger.WithContext(ctx).Create(ledger); err != nil { @@ -2001,7 +2007,7 @@ func (s *super) RejectWithdrawal(ctx context.Context, id int64, reason string) e }) if err == nil && Audit != nil { - Audit.Log(ctx, 0, "reject_withdrawal", cast.ToString(id), "Rejected: "+reason) + Audit.Log(ctx, operatorID, "reject_withdrawal", cast.ToString(id), "Rejected: "+reason) } return err } diff --git a/backend/app/services/super_test.go b/backend/app/services/super_test.go index dad2047..2545421 100644 --- a/backend/app/services/super_test.go +++ b/backend/app/services/super_test.go @@ -105,7 +105,8 @@ func (s *SuperTestSuite) Test_WithdrawalApproval() { database.Truncate(ctx, s.DB, models.TableNameOrder, models.TableNameUser, models.TableNameTenantLedger) u := &models.User{Username: "user_w", Balance: 1000} // Initial 10.00 - models.UserQuery.WithContext(ctx).Create(u) + admin := &models.User{Username: "admin_w"} + models.UserQuery.WithContext(ctx).Create(u, admin) // Create Withdrawal Order (Pending) o1 := &models.Order{ @@ -124,7 +125,7 @@ func (s *SuperTestSuite) Test_WithdrawalApproval() { }) Convey("should approve withdrawal", func() { - err := Super.ApproveWithdrawal(ctx, o1.ID) + err := Super.ApproveWithdrawal(ctx, admin.ID, o1.ID) So(err, ShouldBeNil) oReload, _ := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(o1.ID)).First() @@ -145,7 +146,7 @@ func (s *SuperTestSuite) Test_WithdrawalApproval() { // But here we set balance manually to 1000. Let's assume it was 1200 before. // Current balance 1000. Refund 200 -> Expect 1200. - err := Super.RejectWithdrawal(ctx, o2.ID, "Invalid account") + err := Super.RejectWithdrawal(ctx, admin.ID, o2.ID, "Invalid account") So(err, ShouldBeNil) oReload, _ := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(o2.ID)).First() @@ -158,6 +159,7 @@ func (s *SuperTestSuite) Test_WithdrawalApproval() { l, _ := models.TenantLedgerQuery.WithContext(ctx).Where(models.TenantLedgerQuery.OrderID.Eq(o2.ID)).First() So(l, ShouldNotBeNil) So(l.Type, ShouldEqual, consts.TenantLedgerTypeAdjustment) + So(l.OperatorUserID, ShouldEqual, admin.ID) }) }) } diff --git a/docs/todo_list.md b/docs/todo_list.md index 498f940..7b4a268 100644 --- a/docs/todo_list.md +++ b/docs/todo_list.md @@ -195,6 +195,7 @@ - OTP 登录流程与租户成员校验(未加入拒绝登录)。 - ID 类型已统一为 int64(仅保留 upload_id/external_id/uuid 等非数字标识)。 - 内容资源权限与预览差异化(未购预览、已购/管理员/成员全量)。 +- 审计操作显式传入操作者信息(服务层不再依赖 ctx 读取)。 ## 里程碑建议 - M1:完成 P0