package api import ( "context" "errors" "fmt" "strings" "tyapi-server/internal/application/api/dto" "tyapi-server/internal/domains/api/entities" "tyapi-server/internal/domains/api/repositories" api_services "tyapi-server/internal/domains/api/services" "tyapi-server/internal/shared/interfaces" "go.uber.org/zap" "gorm.io/gorm" ) type QueryWhitelistApplicationService interface { CreateEntry(ctx context.Context, adminUserID string, req *dto.QueryWhitelistEntryRequest) (*dto.QueryWhitelistEntryResponse, error) UpdateEntry(ctx context.Context, adminUserID, id string, req *dto.QueryWhitelistEntryUpdateRequest) (*dto.QueryWhitelistEntryResponse, error) UpdateEntryStatus(ctx context.Context, adminUserID, id, status string) (*dto.QueryWhitelistEntryResponse, error) DeleteEntry(ctx context.Context, id string) error GetEntry(ctx context.Context, id string) (*dto.QueryWhitelistEntryResponse, error) ListEntries(ctx context.Context, filters map[string]interface{}, options interfaces.ListOptions) (*dto.QueryWhitelistListResponse, error) ImportLegacyEntries(ctx context.Context, adminUserID string) (*dto.QueryWhitelistImportLegacyResponse, error) } type QueryWhitelistApplicationServiceImpl struct { repo repositories.QueryWhitelistRepository queryWhitelistSvc api_services.QueryWhitelistService logger *zap.Logger } func NewQueryWhitelistApplicationService( repo repositories.QueryWhitelistRepository, queryWhitelistSvc api_services.QueryWhitelistService, logger *zap.Logger, ) QueryWhitelistApplicationService { return &QueryWhitelistApplicationServiceImpl{ repo: repo, queryWhitelistSvc: queryWhitelistSvc, logger: logger, } } func (s *QueryWhitelistApplicationServiceImpl) CreateEntry( ctx context.Context, adminUserID string, req *dto.QueryWhitelistEntryRequest, ) (*dto.QueryWhitelistEntryResponse, error) { if err := validateQueryWhitelistRequest(req.UserID, req.Name, req.IDCard, req.APICodes); err != nil { return nil, err } idCardHash := api_services.HashIDCard(req.IDCard) exists, err := s.repo.ExistsByUserIDCardHashAndName(ctx, req.UserID, idCardHash, strings.TrimSpace(req.Name), "") if err != nil { return nil, err } if exists { return nil, fmt.Errorf("该用户下已存在相同的身份证与姓名规则") } entry := &entities.QueryWhitelistEntry{ UserID: strings.TrimSpace(req.UserID), Name: normalizeWhitelistName(req.Name), IDCardHash: idCardHash, IDCardMasked: api_services.MaskIDCard(req.IDCard), APICodes: entities.APICodeList(req.APICodes), Status: entities.QueryWhitelistStatusEnabled, Remark: strings.TrimSpace(req.Remark), CreatedBy: &adminUserID, } if err := s.repo.Create(ctx, entry); err != nil { return nil, err } s.queryWhitelistSvc.InvalidateCache(entry.UserID, idCardHash) resp := dto.NewQueryWhitelistEntryResponse(entry) return &resp, nil } func (s *QueryWhitelistApplicationServiceImpl) UpdateEntry( ctx context.Context, adminUserID, id string, req *dto.QueryWhitelistEntryUpdateRequest, ) (*dto.QueryWhitelistEntryResponse, error) { entry, err := s.repo.FindByID(ctx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("规则不存在") } return nil, err } oldHash := entry.IDCardHash if req.Name != "" { entry.Name = normalizeWhitelistName(req.Name) } if req.IDCard != "" { if err := validateIDCard(req.IDCard); err != nil { return nil, err } entry.IDCardHash = api_services.HashIDCard(req.IDCard) entry.IDCardMasked = api_services.MaskIDCard(req.IDCard) } if len(req.APICodes) > 0 { if err := validateAPICodes(req.APICodes); err != nil { return nil, err } entry.APICodes = entities.APICodeList(req.APICodes) } if req.Remark != "" || req.Remark == "" { entry.Remark = strings.TrimSpace(req.Remark) } exists, err := s.repo.ExistsByUserIDCardHashAndName(ctx, entry.UserID, entry.IDCardHash, entry.Name, entry.ID) if err != nil { return nil, err } if exists { return nil, fmt.Errorf("该用户下已存在相同的身份证与姓名规则") } entry.UpdatedBy = &adminUserID if err := s.repo.Update(ctx, entry); err != nil { return nil, err } s.queryWhitelistSvc.InvalidateCache(entry.UserID, oldHash) s.queryWhitelistSvc.InvalidateCache(entry.UserID, entry.IDCardHash) resp := dto.NewQueryWhitelistEntryResponse(entry) return &resp, nil } func (s *QueryWhitelistApplicationServiceImpl) UpdateEntryStatus( ctx context.Context, adminUserID, id, status string, ) (*dto.QueryWhitelistEntryResponse, error) { entry, err := s.repo.FindByID(ctx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("规则不存在") } return nil, err } entry.Status = status entry.UpdatedBy = &adminUserID if err := s.repo.Update(ctx, entry); err != nil { return nil, err } s.queryWhitelistSvc.InvalidateCache(entry.UserID, entry.IDCardHash) resp := dto.NewQueryWhitelistEntryResponse(entry) return &resp, nil } func (s *QueryWhitelistApplicationServiceImpl) DeleteEntry(ctx context.Context, id string) error { entry, err := s.repo.FindByID(ctx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("规则不存在") } return err } if err := s.repo.Delete(ctx, id); err != nil { return err } s.queryWhitelistSvc.InvalidateCache(entry.UserID, entry.IDCardHash) return nil } func (s *QueryWhitelistApplicationServiceImpl) GetEntry(ctx context.Context, id string) (*dto.QueryWhitelistEntryResponse, error) { entry, err := s.repo.FindByID(ctx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("规则不存在") } return nil, err } resp := dto.NewQueryWhitelistEntryResponse(entry) return &resp, nil } func (s *QueryWhitelistApplicationServiceImpl) ListEntries( ctx context.Context, filters map[string]interface{}, options interfaces.ListOptions, ) (*dto.QueryWhitelistListResponse, error) { if idCard, ok := filters["id_card"].(string); ok && idCard != "" { filters["id_card_hash"] = api_services.HashIDCard(idCard) delete(filters, "id_card") } entries, total, err := s.repo.List(ctx, filters, options) if err != nil { return nil, err } items := make([]dto.QueryWhitelistEntryResponse, 0, len(entries)) for _, entry := range entries { items = append(items, dto.NewQueryWhitelistEntryResponse(entry)) } page := options.Page if page < 1 { page = 1 } size := options.PageSize if size < 1 { size = 20 } return &dto.QueryWhitelistListResponse{ Items: items, Total: total, Page: page, Size: size, }, nil } func (s *QueryWhitelistApplicationServiceImpl) ImportLegacyEntries( ctx context.Context, adminUserID string, ) (*dto.QueryWhitelistImportLegacyResponse, error) { imported := 0 skipped := 0 for _, idCard := range LegacyHardcodedIDCards { hash := api_services.HashIDCard(idCard) exists, err := s.repo.ExistsByUserIDCardHashAndName( ctx, entities.QueryWhitelistGlobalUserID, hash, entities.QueryWhitelistWildcardName, "", ) if err != nil { return nil, err } if exists { skipped++ continue } entry := &entities.QueryWhitelistEntry{ UserID: entities.QueryWhitelistGlobalUserID, Name: entities.QueryWhitelistWildcardName, IDCardHash: hash, IDCardMasked: api_services.MaskIDCard(idCard), APICodes: entities.APICodeList{"*"}, Status: entities.QueryWhitelistStatusEnabled, Remark: "自硬编码迁移-全局", CreatedBy: &adminUserID, } if err := s.repo.Create(ctx, entry); err != nil { return nil, err } s.queryWhitelistSvc.InvalidateCache(entities.QueryWhitelistGlobalUserID, hash) imported++ } return &dto.QueryWhitelistImportLegacyResponse{ Imported: imported, Skipped: skipped, Total: len(LegacyHardcodedIDCards), }, nil } func validateQueryWhitelistRequest(userID, name, idCard string, apiCodes []string) error { userID = strings.TrimSpace(userID) if userID == "" { return fmt.Errorf("user_id 不能为空") } if strings.TrimSpace(name) == "" { return fmt.Errorf("name 不能为空") } if err := validateIDCard(idCard); err != nil { return err } return validateAPICodes(apiCodes) } func validateIDCard(idCard string) error { idCard = api_services.NormalizeIDCard(idCard) if len(idCard) != 18 { return fmt.Errorf("身份证号格式不正确") } return nil } func validateAPICodes(apiCodes []string) error { if len(apiCodes) == 0 { return fmt.Errorf("api_codes 不能为空") } hasWildcard := false for _, code := range apiCodes { code = strings.TrimSpace(code) if code == "" { return fmt.Errorf("api_codes 不能包含空值") } if code == "*" { hasWildcard = true } } if hasWildcard && len(apiCodes) > 1 { return fmt.Errorf("api_codes 包含 * 时不能与其他编码混用") } return nil } func normalizeWhitelistName(name string) string { name = strings.TrimSpace(name) if name == entities.QueryWhitelistWildcardName { return entities.QueryWhitelistWildcardName } return name }