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 }) }