addf
This commit is contained in:
303
app/main/api/internal/service/querywhitelistsync.go
Normal file
303
app/main/api/internal/service/querywhitelistsync.go
Normal file
@@ -0,0 +1,303 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"ycc-server/app/main/api/internal/config"
|
||||
tianyuanapi "ycc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
var queryWhitelistIdCardPattern = regexp.MustCompile(`^\d{17}[\dXx]$`)
|
||||
|
||||
const (
|
||||
tianyuanQueryWhitelistSuccessCode = 0
|
||||
tianyuanQueryWhitelistExistsCode = 1013
|
||||
tianyuanQueryWhitelistNotFoundCode = 1014
|
||||
tianyuanQueryWhitelistLocalFailCode = -1
|
||||
)
|
||||
|
||||
// QueryWhitelistSyncService 天远查询白名单同步服务
|
||||
type QueryWhitelistSyncService struct {
|
||||
config config.Config
|
||||
client *tianyuanapi.Client
|
||||
opLogModel model.QueryWhitelistOpLogModel
|
||||
}
|
||||
|
||||
func NewQueryWhitelistSyncService(
|
||||
c config.Config,
|
||||
client *tianyuanapi.Client,
|
||||
opLogModel model.QueryWhitelistOpLogModel,
|
||||
) *QueryWhitelistSyncService {
|
||||
return &QueryWhitelistSyncService{
|
||||
config: c,
|
||||
client: client,
|
||||
opLogModel: opLogModel,
|
||||
}
|
||||
}
|
||||
|
||||
// TrySync 尽力同步天远查询白名单,失败仅记操作日志,不影响主流程
|
||||
func (s *QueryWhitelistSyncService) TrySync(
|
||||
ctx context.Context,
|
||||
name, idCard string,
|
||||
apiCodes []string,
|
||||
remark string,
|
||||
) {
|
||||
if err := s.Sync(ctx, name, idCard, apiCodes, remark); err != nil {
|
||||
logx.WithContext(ctx).Errorf("天远查询白名单同步失败(不影响主流程): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TrySyncWhitelistOrder 尽力同步白名单订单中的模块到天远
|
||||
func (s *QueryWhitelistSyncService) TrySyncWhitelistOrder(
|
||||
ctx context.Context,
|
||||
whitelistOrder *model.WhitelistOrder,
|
||||
items []*model.WhitelistOrderItem,
|
||||
remark string,
|
||||
) {
|
||||
if whitelistOrder == nil || len(items) == 0 {
|
||||
return
|
||||
}
|
||||
s.TrySync(ctx, "*", whitelistOrder.IdCard, collectWhitelistOrderApiCodes(items), remark)
|
||||
}
|
||||
|
||||
// Sync 将产品编码同步到天远查询白名单(先追加,规则不存在则创建)
|
||||
func (s *QueryWhitelistSyncService) Sync(
|
||||
ctx context.Context,
|
||||
name, idCard string,
|
||||
apiCodes []string,
|
||||
remark string,
|
||||
) error {
|
||||
if err := validateQueryWhitelistSyncReq(idCard, apiCodes); err != nil {
|
||||
s.recordOpLogFailure(ctx, "sync", name, idCard, apiCodes, remark, err.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||
return err
|
||||
}
|
||||
|
||||
appendResp, err := s.callMgmt(
|
||||
"/api/v1/query-whitelist/entries/append",
|
||||
name,
|
||||
idCard,
|
||||
apiCodes,
|
||||
remark,
|
||||
)
|
||||
if err != nil {
|
||||
s.recordOpLogFailure(ctx, "append", name, idCard, apiCodes, remark, err.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||
return err
|
||||
}
|
||||
if isTianyuanQueryWhitelistSuccess(appendResp.Code) {
|
||||
s.recordOpLog(ctx, "append", name, idCard, apiCodes, remark, appendResp)
|
||||
return nil
|
||||
}
|
||||
if appendResp.Code != tianyuanQueryWhitelistNotFoundCode {
|
||||
s.recordOpLog(ctx, "append", name, idCard, apiCodes, remark, appendResp)
|
||||
return errors.Wrapf(xerr.NewErrMsg(appendResp.Message), "天远查询白名单同步失败(code=%d)", appendResp.Code)
|
||||
}
|
||||
|
||||
createResp, err := s.callMgmt(
|
||||
"/api/v1/query-whitelist/entries",
|
||||
name,
|
||||
idCard,
|
||||
apiCodes,
|
||||
remark,
|
||||
)
|
||||
if err != nil {
|
||||
s.recordOpLogFailure(ctx, "create", name, idCard, apiCodes, remark, err.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||
return err
|
||||
}
|
||||
if isTianyuanQueryWhitelistSuccess(createResp.Code) {
|
||||
s.recordOpLog(ctx, "create", name, idCard, apiCodes, remark, createResp)
|
||||
return nil
|
||||
}
|
||||
if createResp.Code == tianyuanQueryWhitelistExistsCode {
|
||||
retryResp, retryErr := s.callMgmt(
|
||||
"/api/v1/query-whitelist/entries/append",
|
||||
name,
|
||||
idCard,
|
||||
apiCodes,
|
||||
remark,
|
||||
)
|
||||
if retryErr != nil {
|
||||
s.recordOpLogFailure(ctx, "append", name, idCard, apiCodes, remark, retryErr.Error(), tianyuanQueryWhitelistLocalFailCode)
|
||||
return retryErr
|
||||
}
|
||||
s.recordOpLog(ctx, "append", name, idCard, apiCodes, remark, retryResp)
|
||||
if isTianyuanQueryWhitelistSuccess(retryResp.Code) {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrMsg(retryResp.Message), "天远查询白名单同步失败(code=%d)", retryResp.Code)
|
||||
}
|
||||
|
||||
s.recordOpLog(ctx, "create", name, idCard, apiCodes, remark, createResp)
|
||||
return errors.Wrapf(xerr.NewErrMsg(createResp.Message), "天远查询白名单同步失败(code=%d)", createResp.Code)
|
||||
}
|
||||
|
||||
func collectWhitelistOrderApiCodes(items []*model.WhitelistOrderItem) []string {
|
||||
codes := make([]string, 0, len(items))
|
||||
seen := make(map[string]bool, len(items))
|
||||
for _, item := range items {
|
||||
if item == nil || item.FeatureApiId == "" || seen[item.FeatureApiId] {
|
||||
continue
|
||||
}
|
||||
seen[item.FeatureApiId] = true
|
||||
codes = append(codes, item.FeatureApiId)
|
||||
}
|
||||
return codes
|
||||
}
|
||||
|
||||
func validateQueryWhitelistSyncReq(idCard string, apiCodes []string) error {
|
||||
if strings.TrimSpace(idCard) == "" {
|
||||
return errors.Wrapf(xerr.NewErrMsg("身份证号不能为空"), "")
|
||||
}
|
||||
if !queryWhitelistIdCardPattern.MatchString(strings.TrimSpace(idCard)) {
|
||||
return errors.Wrapf(xerr.NewErrMsg("身份证号格式不正确,需为18位中国大陆身份证号"), "")
|
||||
}
|
||||
if len(apiCodes) == 0 {
|
||||
return errors.Wrapf(xerr.NewErrMsg("请至少选择一个产品编码"), "")
|
||||
}
|
||||
for _, code := range apiCodes {
|
||||
if strings.TrimSpace(code) == "" {
|
||||
return errors.Wrapf(xerr.NewErrMsg("产品编码不能为空"), "")
|
||||
}
|
||||
if code == "*" {
|
||||
return errors.Wrapf(xerr.NewErrMsg("产品编码不支持通配符 *"), "")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *QueryWhitelistSyncService) callMgmt(
|
||||
apiPath string,
|
||||
name, idCard string,
|
||||
apiCodes []string,
|
||||
remark string,
|
||||
) (*tianyuanapi.QueryWhitelistMgmtResponse, error) {
|
||||
mgmtKey := s.config.Tianyuanapi.WhitelistMgmtKey
|
||||
if mgmtKey == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("查询白名单管理密钥未配置,请在服务端配置 Tianyuanapi.WhitelistMgmtKey"), "")
|
||||
}
|
||||
if s.client == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("天远 API 客户端未初始化"), "")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(name) == "" {
|
||||
name = "*"
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"name": name,
|
||||
"id_card": strings.TrimSpace(idCard),
|
||||
"api_codes": apiCodes,
|
||||
}
|
||||
if strings.TrimSpace(remark) != "" {
|
||||
payload["remark"] = strings.TrimSpace(remark)
|
||||
}
|
||||
|
||||
return s.client.CallQueryWhitelistMgmt(apiPath, payload, mgmtKey)
|
||||
}
|
||||
|
||||
func (s *QueryWhitelistSyncService) recordOpLogFailure(
|
||||
ctx context.Context,
|
||||
action, name, idCard string,
|
||||
apiCodes []string,
|
||||
remark, message string,
|
||||
code int64,
|
||||
) {
|
||||
s.insertOpLog(ctx, action, name, idCard, apiCodes, remark, code, message, "", nil)
|
||||
}
|
||||
|
||||
func (s *QueryWhitelistSyncService) recordOpLog(
|
||||
ctx context.Context,
|
||||
action, name, idCard string,
|
||||
apiCodes []string,
|
||||
remark string,
|
||||
apiResp *tianyuanapi.QueryWhitelistMgmtResponse,
|
||||
) {
|
||||
if apiResp == nil {
|
||||
return
|
||||
}
|
||||
s.insertOpLog(ctx, action, name, idCard, apiCodes, remark, int64(apiResp.Code), apiResp.Message, apiResp.TransactionID, apiResp.Entry)
|
||||
}
|
||||
|
||||
func (s *QueryWhitelistSyncService) insertOpLog(
|
||||
ctx context.Context,
|
||||
action, name, idCard string,
|
||||
apiCodes []string,
|
||||
remark string,
|
||||
tianyuanCode int64,
|
||||
tianyuanMessage, transactionID string,
|
||||
entry *tianyuanapi.QueryWhitelistEntry,
|
||||
) {
|
||||
if s.opLogModel == nil {
|
||||
return
|
||||
}
|
||||
|
||||
operatorUserId, err := ctxdata.GetUidFromCtx(ctx)
|
||||
if err != nil {
|
||||
logx.WithContext(ctx).Errorf("记录查询白名单操作日志失败: 获取操作人ID失败, %v", err)
|
||||
operatorUserId = ""
|
||||
}
|
||||
|
||||
apiCodesJSON, marshalErr := json.Marshal(apiCodes)
|
||||
if marshalErr != nil {
|
||||
logx.WithContext(ctx).Errorf("记录查询白名单操作日志失败: 序列化 api_codes 失败, %v", marshalErr)
|
||||
return
|
||||
}
|
||||
|
||||
log := &model.QueryWhitelistOpLog{
|
||||
AdminUserId: operatorUserId,
|
||||
Action: action,
|
||||
Name: resolveQueryWhitelistName(name),
|
||||
IdCard: strings.TrimSpace(idCard),
|
||||
ApiCodes: string(apiCodesJSON),
|
||||
TianyuanCode: tianyuanCode,
|
||||
}
|
||||
|
||||
if strings.TrimSpace(remark) != "" {
|
||||
log.Remark = sql.NullString{String: strings.TrimSpace(remark), Valid: true}
|
||||
}
|
||||
if tianyuanMessage != "" {
|
||||
log.TianyuanMessage = sql.NullString{String: tianyuanMessage, Valid: true}
|
||||
}
|
||||
if transactionID != "" {
|
||||
log.TransactionId = sql.NullString{String: transactionID, Valid: true}
|
||||
}
|
||||
if entry != nil {
|
||||
if entry.IdCardMasked != "" {
|
||||
log.IdCardMasked = sql.NullString{String: entry.IdCardMasked, Valid: true}
|
||||
}
|
||||
if entry.ID != "" {
|
||||
log.EntryId = sql.NullString{String: entry.ID, Valid: true}
|
||||
}
|
||||
if entry.Status != "" {
|
||||
log.EntryStatus = sql.NullString{String: entry.Status, Valid: true}
|
||||
}
|
||||
if len(entry.ApiCodes) > 0 {
|
||||
entryCodesJSON, _ := json.Marshal(entry.ApiCodes)
|
||||
log.EntryApiCodes = sql.NullString{String: string(entryCodesJSON), Valid: true}
|
||||
}
|
||||
}
|
||||
|
||||
if _, insertErr := s.opLogModel.Insert(ctx, nil, log); insertErr != nil {
|
||||
logx.WithContext(ctx).Errorf("记录查询白名单操作日志失败: %v", insertErr)
|
||||
}
|
||||
}
|
||||
|
||||
func resolveQueryWhitelistName(name string) string {
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return "*"
|
||||
}
|
||||
return strings.TrimSpace(name)
|
||||
}
|
||||
|
||||
func isTianyuanQueryWhitelistSuccess(code int) bool {
|
||||
return code == tianyuanQueryWhitelistSuccessCode
|
||||
}
|
||||
Reference in New Issue
Block a user