Files
tyapi-server/internal/application/api/query_whitelist_application_service.go
2026-06-18 21:37:43 +08:00

310 lines
9.0 KiB
Go

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(LegacyHardcodedAPICodes),
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
}