소스 검색

fix(client): delete external-link rows when bulk-deleting clients

The single-client Delete path removes a client's client_external_links rows,
but BulkDelete (and the DelDepleted reaper that routes through it) deleted the
record, mappings and traffic while leaving the external-link rows keyed by the
now-dead client id, so they accumulated as orphans. Delete them in the same
cleanup transaction, keyed by client id like the single path.
MHSanaei 1 일 전
부모
커밋
91e1e5eeff
2개의 변경된 파일32개의 추가작업 그리고 0개의 파일을 삭제
  1. 29 0
      internal/web/service/bulk_traffic_test.go
  2. 3 0
      internal/web/service/client_bulk.go

+ 29 - 0
internal/web/service/bulk_traffic_test.go

@@ -146,6 +146,35 @@ func TestClientDeleteKeepTrafficPreservesRowForAttachedClient(t *testing.T) {
 	}
 }
 
+func TestBulkDeleteRemovesClientExternalLinks(t *testing.T) {
+	setupBulkDB(t)
+	svc := &ClientService{}
+	inboundSvc := &InboundService{}
+
+	email := "extlink@x"
+	c := model.Client{Email: email, ID: "11111111-1111-1111-1111-111111111111", SubID: email, Enable: true}
+	ib := mkInbound(t, 52040, model.VLESS, clientsSettings(t, []model.Client{c}))
+	if err := svc.SyncInbound(nil, ib.Id, []model.Client{c}); err != nil {
+		t.Fatalf("seed linkage: %v", err)
+	}
+	rec := lookupClientRecord(t, email)
+	if err := database.GetDB().Create(&model.ClientExternalLink{ClientId: rec.Id, Kind: "sub", Value: "https://example.com/x"}).Error; err != nil {
+		t.Fatalf("seed external link: %v", err)
+	}
+
+	if _, _, err := svc.BulkDelete(inboundSvc, []string{email}, false); err != nil {
+		t.Fatalf("BulkDelete: %v", err)
+	}
+
+	var cnt int64
+	if err := database.GetDB().Model(&model.ClientExternalLink{}).Where("client_id = ?", rec.Id).Count(&cnt).Error; err != nil {
+		t.Fatalf("count external links: %v", err)
+	}
+	if cnt != 0 {
+		t.Fatalf("BulkDelete left %d orphan external-link row(s) behind", cnt)
+	}
+}
+
 func TestGetClientTrafficByEmailReadsClientsTable(t *testing.T) {
 	setupBulkDB(t)
 	svc := &ClientService{}

+ 3 - 0
internal/web/service/client_bulk.go

@@ -855,6 +855,9 @@ func (s *ClientService) BulkDelete(inboundSvc *InboundService, emails []string,
 				if e := tx.Where("client_id IN ?", batch).Delete(&model.ClientInbound{}).Error; e != nil {
 					return e
 				}
+				if e := tx.Where("client_id IN ?", batch).Delete(&model.ClientExternalLink{}).Error; e != nil {
+					return e
+				}
 			}
 			if !keepTraffic && len(successEmails) > 0 {
 				for _, batch := range chunkStrings(successEmails, sqlInChunk) {