From 1f39bf8a7870a47241c92aa7bd019807c8409d80 Mon Sep 17 00:00:00 2001 From: YilinMacAir Date: Fri, 27 Mar 2026 16:37:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E7=94=B1=E4=BA=8E?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=94=AF=E4=B8=80=E9=94=AE=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E8=BD=AF=E5=88=A0=E9=99=A4apikey=E5=90=8Ekey=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E8=A2=AB=E9=87=8A=E6=94=BE=E5=90=8E=E7=BB=AD=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E5=86=8D=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9B=B8=E5=90=8C?= =?UTF-8?q?=E7=9A=84key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/repository/api_key_repo.go | 4 +++ .../api_key_repo_integration_test.go | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/backend/internal/repository/api_key_repo.go b/backend/internal/repository/api_key_repo.go index 859eefd5..667193a6 100644 --- a/backend/internal/repository/api_key_repo.go +++ b/backend/internal/repository/api_key_repo.go @@ -3,6 +3,7 @@ package repository import ( "context" "database/sql" + "fmt" "time" dbent "github.com/Wei-Shaw/sub2api/ent" @@ -257,9 +258,12 @@ func (r *apiKeyRepository) Update(ctx context.Context, key *service.APIKey) erro } func (r *apiKeyRepository) Delete(ctx context.Context, id int64) error { + // 存在唯一键约束 生成tombstone key 用来释放原key,长度远小于 128,满足 schema 限制 + tombstoneKey := fmt.Sprintf("__deleted__%d__%d", id, time.Now().UnixNano()) // 显式软删除:避免依赖 Hook 行为,确保 deleted_at 一定被设置。 affected, err := r.client.APIKey.Update(). Where(apikey.IDEQ(id), apikey.DeletedAtIsNil()). + SetKey(tombstoneKey). SetDeletedAt(time.Now()). Save(ctx) if err != nil { diff --git a/backend/internal/repository/api_key_repo_integration_test.go b/backend/internal/repository/api_key_repo_integration_test.go index a8989ff2..7d5c1826 100644 --- a/backend/internal/repository/api_key_repo_integration_test.go +++ b/backend/internal/repository/api_key_repo_integration_test.go @@ -151,6 +151,31 @@ func (s *APIKeyRepoSuite) TestDelete() { s.Require().Error(err, "expected error after delete") } +func (s *APIKeyRepoSuite) TestCreate_AfterSoftDelete_AllowsSameKey() { + user := s.mustCreateUser("recreate-after-soft-delete@test.com") + const reusedKey = "sk-reuse-after-soft-delete" + + first := &service.APIKey{ + UserID: user.ID, + Key: reusedKey, + Name: "First Key", + Status: service.StatusActive, + } + s.Require().NoError(s.repo.Create(s.ctx, first), "create first key") + + s.Require().NoError(s.repo.Delete(s.ctx, first.ID), "soft delete first key") + + second := &service.APIKey{ + UserID: user.ID, + Key: reusedKey, + Name: "Second Key", + Status: service.StatusActive, + } + s.Require().NoError(s.repo.Create(s.ctx, second), "create second key with same key") + s.Require().NotZero(second.ID) + s.Require().NotEqual(first.ID, second.ID, "recreated key should be a new row") +} + // --- ListByUserID / CountByUserID --- func (s *APIKeyRepoSuite) TestListByUserID() {