haibei/internal/mods/customer/biz/customer.biz.go
2025-06-19 10:33:58 +08:00

240 lines
6.3 KiB
Go

package biz
import (
"context"
"encoding/json"
"fmt"
"github.guxuan/haibei/internal/config"
"github.guxuan/haibei/pkg/cachex"
"github.guxuan/haibei/pkg/jwtx"
"github.guxuan/haibei/pkg/logging"
"go.uber.org/zap"
"math/rand"
"strconv"
"time"
"github.guxuan/haibei/internal/mods/customer/dal"
"github.guxuan/haibei/internal/mods/customer/schema"
"github.guxuan/haibei/pkg/errors"
"github.guxuan/haibei/pkg/util"
)
const (
REGISTER_SMS_CODE = "REGISTER_SMS_CODE"
CHECK_SMS_CODE = "CHECK_SMS_CODE"
)
// Defining the `Customer` business logic.
type Customer struct {
Cache cachex.Cacher
Trans *util.Trans
CustomerDAL *dal.Customer
Auth jwtx.Auther
}
func (a *Customer) Login(ctx context.Context, formItem *schema.CustomerLoginForm) (*schema.CustomerLoginToken, error) {
ctx = logging.NewTag(ctx, logging.TagKeyAppLogin)
// get user info
user, err := a.CustomerDAL.GetByWxSign(ctx, formItem.WxSign, schema.CustomerQueryOptions{})
if err != nil {
return nil, err
}
if user == nil {
customer := &schema.Customer{}
customer.WxSign = formItem.WxSign
err := a.CustomerDAL.Create(ctx, customer)
if err != nil {
return nil, err
}
user = customer
}
userID := fmt.Sprintf("%d", user.ID)
var subject jwtx.JwtSubject
subject.ID = userID
subject.Typer = "APP"
marshal, err := json.Marshal(subject)
if err != nil {
return nil, err
}
// generate token
ctx = logging.NewUserID(ctx, userID)
userCache := util.UserCache{RoleIDs: []string{}}
err = a.Cache.Set(ctx, config.CacheNSForUser, userID, userCache.String(),
time.Duration(config.C.Dictionary.UserCacheExp)*time.Hour)
if err != nil {
logging.Context(ctx).Error("Failed to set cache", zap.Error(err))
}
logging.Context(ctx).Info("Login success", zap.String("WxSign", formItem.WxSign))
reload, err := a.genCustomerToken(ctx, string(marshal))
reload.Phone = user.Phone
return reload, err
}
func (a *Customer) BindPhone(ctx context.Context, formItem *schema.CustomerBindPhoneForm) (bool, error) {
userID := util.FromUserID(ctx)
num, err := strconv.ParseUint(fmt.Sprintf("%s", userID), 10, 64)
if err != nil {
fmt.Println("转换错误:", err)
return false, err
}
userIDNum := uint(num)
code, b, err := a.Cache.Get(ctx, REGISTER_SMS_CODE, formItem.Phone)
if err != nil {
return false, err
}
if !b {
return false, errors.NotFound("", "验证码过期!")
}
if code != formItem.Code {
return false, errors.NotFound("", "验证码失败!")
}
get, err := a.CustomerDAL.Get(ctx, userIDNum, schema.CustomerQueryOptions{})
if err != nil || get == nil {
return false, err
}
get.Phone = formItem.Phone
get.Avatar = formItem.Avatar
err = a.CustomerDAL.Update(ctx, get)
if err != nil {
return false, err
}
return true, nil
}
func (a *Customer) SendSms(ctx context.Context, phone string) (string, error) {
code := generateVerificationCode()
exists, err := a.Cache.Exists(ctx, REGISTER_SMS_CODE, phone)
if err != nil {
return "", err
}
if exists {
return "", errors.NotFound("", "验证码不能重复获取 等待90秒")
}
err = sendVerificationCode(phone, code)
if err != nil {
return "", err
}
err = a.Cache.Set(ctx, REGISTER_SMS_CODE, phone, code, 90*time.Second)
if err != nil {
return "", err
}
return code, nil
}
func sendVerificationCode(phone, code string) error {
// 这里应该是调用短信服务商的API发送短信
// 这里只是模拟
fmt.Printf("向手机号 %s 发送验证码: %s\n", phone, code)
return nil
}
func generateVerificationCode() string {
rand.Seed(time.Now().UnixNano())
return fmt.Sprintf("%06d", rand.Intn(1000000))
}
func (a *Customer) genCustomerToken(ctx context.Context, suject string) (*schema.CustomerLoginToken, error) {
token, err := a.Auth.GenerateToken(ctx, suject)
if err != nil {
return nil, err
}
tokenBuf, err := token.EncodeToJSON()
if err != nil {
return nil, err
}
logging.Context(ctx).Info("Generate user token", zap.Any("token", string(tokenBuf)))
return &schema.CustomerLoginToken{
AccessToken: token.GetAccessToken(),
TokenType: token.GetTokenType(),
ExpiresAt: token.GetExpiresAt(),
}, nil
}
// Query customers from the data access object based on the provided parameters and options.
func (a *Customer) Query(ctx context.Context, params schema.CustomerQueryParam) (*schema.CustomerQueryResult, error) {
params.Pagination = true
result, err := a.CustomerDAL.Query(ctx, params, schema.CustomerQueryOptions{
QueryOptions: util.QueryOptions{
OrderFields: []util.OrderByParam{
{Field: "created_at", Direction: util.DESC},
},
},
})
if err != nil {
return nil, err
}
return result, nil
}
// Get the specified customer from the data access object.
func (a *Customer) Get(ctx context.Context, id uint) (*schema.Customer, error) {
customer, err := a.CustomerDAL.Get(ctx, id)
if err != nil {
return nil, err
} else if customer == nil {
return nil, errors.NotFound("", "Customer not found")
}
return customer, nil
}
// Create a new customer in the data access object.
func (a *Customer) Create(ctx context.Context, formItem *schema.CustomerForm) (*schema.Customer, error) {
customer := &schema.Customer{}
if err := formItem.FillTo(customer); err != nil {
return nil, err
}
err := a.Trans.Exec(ctx, func(ctx context.Context) error {
if err := a.CustomerDAL.Create(ctx, customer); err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return customer, nil
}
// Update the specified customer in the data access object.
func (a *Customer) Update(ctx context.Context, id uint, formItem *schema.CustomerForm) error {
customer, err := a.CustomerDAL.Get(ctx, id)
if err != nil {
return err
} else if customer == nil {
return errors.NotFound("", "Customer not found")
}
if err := formItem.FillTo(customer); err != nil {
return err
}
customer.UpdatedAt = time.Now()
return a.Trans.Exec(ctx, func(ctx context.Context) error {
if err := a.CustomerDAL.Update(ctx, customer); err != nil {
return err
}
return nil
})
}
// Delete the specified customer from the data access object.
func (a *Customer) Delete(ctx context.Context, id uint) error {
exists, err := a.CustomerDAL.Exists(ctx, id)
if err != nil {
return err
} else if !exists {
return errors.NotFound("", "Customer not found")
}
return a.Trans.Exec(ctx, func(ctx context.Context) error {
if err := a.CustomerDAL.Delete(ctx, id); err != nil {
return err
}
return nil
})
}