Files
hfb_sys/backend/internal/modules/realname/service.go
T
yml2213 b377f8350b 为 9 个模块添加 Context 超时控制
完成模块:
- auth: 3 个 Repository 方法 + Service + Handler + Middleware
- wallet: 已有 context 支持,修复依赖调用
- payment: 已有 context 支持,修复 wallet 调用
- adminaudit: 1 个方法
- notification: 2 个方法
- realname: 2 个方法
- systemconfig: 4 个方法
- adminauth: 7 个方法
- adminuser: 6 个方法

所有数据库调用已改为 r.db.WithContext(ctx),完整传递 context 链路。

待完成模块: order, listing, chat 等 12 个模块(约 157 个方法)
2026-06-10 09:12:27 +08:00

112 lines
2.9 KiB
Go

package realname
import (
"context"
"errors"
"regexp"
"strings"
"hfb_sys/backend/internal/model"
"go.uber.org/zap"
)
const (
StatusPending = "pending"
StatusVerified = "verified"
StatusRejected = "rejected"
)
var (
ErrDependencyUnavailable = errors.New("dependency unavailable")
ErrInvalidRealnameInput = errors.New("invalid realname input")
ErrProviderConfigInvalid = errors.New("realname provider config invalid")
ErrProviderRateLimited = errors.New("realname provider rate limited")
ErrProviderUnavailable = errors.New("realname provider unavailable")
)
type Service struct {
repo *Repository
provider Provider
log *zap.Logger
}
type PublicStatus struct {
Status string `json:"status"`
Provider string `json:"provider,omitempty"`
ProviderOrderNo string `json:"provider_order_no,omitempty"`
MaskedName string `json:"masked_name,omitempty"`
MaskedIDNo string `json:"masked_id_no,omitempty"`
VerifiedAt *string `json:"verified_at,omitempty"`
FailReason string `json:"fail_reason,omitempty"`
}
func NewService(repo *Repository, provider Provider, log *zap.Logger) *Service {
return &Service{repo: repo, provider: provider, log: log}
}
func (s *Service) Start(ctx context.Context, userID uint64, name string, idNo string) (*model.UserRealname, error) {
if s.repo == nil || s.provider == nil {
return nil, ErrDependencyUnavailable
}
name = strings.TrimSpace(name)
idNo = strings.TrimSpace(idNo)
if !validName(name) || !validIDNo(idNo) {
return nil, ErrInvalidRealnameInput
}
result, err := s.provider.Start(ctx, StartRequest{
UserID: userID,
Name: name,
IDNo: idNo,
})
if err != nil {
if s.log != nil {
s.log.Warn(
"realname provider verify failed",
zap.String("provider", s.provider.Name()),
zap.Uint64("user_id", userID),
zap.String("masked_id_no", maskIDNo(idNo)),
zap.Error(err),
)
}
return nil, err
}
return s.repo.SaveResult(ctx, userID, s.provider.Name(), result)
}
func (s *Service) Status(ctx context.Context, userID uint64) (PublicStatus, error) {
if s.repo == nil {
return PublicStatus{}, ErrDependencyUnavailable
}
record, err := s.repo.FindByUserID(ctx, userID)
if err != nil {
return PublicStatus{Status: "unverified"}, nil
}
return ToPublicStatus(record), nil
}
func ToPublicStatus(record *model.UserRealname) PublicStatus {
var verifiedAt *string
if record.VerifiedAt != nil {
value := record.VerifiedAt.Format("2006-01-02 15:04:05")
verifiedAt = &value
}
return PublicStatus{
Status: record.Status,
Provider: record.Provider,
ProviderOrderNo: record.ProviderOrderNo,
MaskedName: record.MaskedName,
MaskedIDNo: record.MaskedIDNo,
VerifiedAt: verifiedAt,
FailReason: record.FailReason,
}
}
func validName(name string) bool {
return len([]rune(name)) >= 2 && len([]rune(name)) <= 30
}
func validIDNo(idNo string) bool {
return regexp.MustCompile(`^\d{17}[\dXx]$`).MatchString(idNo)
}