@@ -2,18 +2,23 @@ package user
import (
"context"
"database/sql"
"errors"
"fmt"
"os"
"time"
"bdrp-server/app/main/api/internal/svc"
"bdrp-server/app/main/api/internal/types"
"bdrp-server/app/main/model"
"bdrp-server/common/ctxdata"
"bdrp-server/common/xerr"
"bdrp-server/pkg/lzkit/crypto"
"github.com/zeromicro/go-zero/core/mr "
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"bdrp-server/app/main/api/internal/svc"
pkgerrors "github.com/pkg/errors "
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type CancelOutLogic struct {
@@ -30,222 +35,122 @@ func NewCancelOutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelO
}
}
func ( l * CancelOutLogic ) CancelOut ( ) error {
userID , getUserIdErr := ctxdata . GetUidFromCtx ( l . ctx )
if getUserIdErr != nil {
return errors . Wrapf ( xerr . NewErrCode ( xerr . SERVER_COMMON_ERROR ) , "用户信息, %v" , getUserIdErr )
// cancelledMobilePlain 生成唯一占位明文手机号( 11 位),用于释放真实手机号唯一约束
func cancelledMobilePlain ( userID int64 ) string {
return fmt . Sprintf ( "199%09d" , userID % 1000000000 )
}
func ( l * CancelOutLogic ) CancelOut ( req * types . CancelOutReq ) error {
userID , err := ctxdata . GetUidFromCtx ( l . ctx )
if err != nil {
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . SERVER_COMMON_ERROR ) , "用户信息, %v" , err )
}
user , err := l . svcCtx . UserModel . FindOne ( l . ctx , userID )
if err != nil {
if errors . Is ( err , model . ErrNotFound ) {
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . USER_NOT_FOUND ) , "用户不存在" )
}
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . DB_ERROR ) , "查询用户失败: %v" , err )
}
if user . Disable == 1 {
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . USER_DISABLED ) , "账号已被封禁" )
}
if user . CancelledAt . Valid {
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . USER_CANCELLED ) , "账号已注销" )
}
if ! user . Mobile . Valid || user . Mobile . String == "" {
return pkgerrors . Wrapf ( xerr . NewErrMsg ( "请先绑定手机号后再注销账号" ) , "注销账号, 未绑定手机号 userId=%d" , userID )
}
secretKey := l . svcCtx . Config . Encrypt . SecretKey
encryptedMobile := user . Mobile . String
if os . Getenv ( "ENV" ) != "development" {
codeKey := fmt . Sprintf ( "%s:%s" , "cancelAccount" , encryptedMobile )
cacheCode , err := l . svcCtx . Redis . Get ( codeKey )
if err != nil {
if errors . Is ( err , redis . Nil ) {
return pkgerrors . Wrapf ( xerr . NewErrMsg ( "验证码已过期" ) , "注销账号, 验证码过期" )
}
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . DB_ERROR ) , "注销账号, 读取验证码失败: %v" , err )
}
if cacheCode != req . Code {
return pkgerrors . Wrapf ( xerr . NewErrMsg ( "验证码不正确" ) , "注销账号, 验证码不正确" )
}
}
placeholderPlain := cancelledMobilePlain ( userID )
placeholderEnc , err := crypto . EncryptMobile ( placeholderPlain , secretKey )
if err != nil {
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . SERVER_COMMON_ERROR ) , "注销账号, 生成占位手机号失败: %v" , err )
}
// 1. 先检查用户是否是代理
agentModel , err := l . svcCtx . AgentModel . FindOneByUserId ( l . ctx , userID )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询代理信息失败, userId : %d " , userID )
return pkg errors. Wrapf ( x err. NewErrCode ( xerr . DB_ERROR ) , "查询代理信息失败: %v " , err )
}
// 如果用户是代理,进行额外检查
if agentModel != nil {
// 1.1 检查代理等级是否为VIP或SVIP
if agentModel . LevelName == model . AgentLeveNameVIP || agentModel . LevelName == model . AgentLeveNameSVIP {
return errors . Wrapf ( xerr . NewErrMsg ( "您是" + agentModel . LevelName + "会员,请联系客服进行注销" ) , "用户是代理会员,不能注销" )
}
// 1.2 检查代理钱包是否有余额或冻结金额
wallet , err := l . svcCtx . AgentWalletModel . FindOneByAgentId ( l . ctx , agentModel . Id )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( xerr . NewErrCode ( xerr . DB_ERROR ) , "查询代理钱包失败, agentId: %d" , agentModel . Id )
}
if wallet != nil && ( wallet . Balance > 0 || wallet . FrozenBalance > 0 ) {
if wallet . Balance > 0 {
return errors . Wrapf ( xerr . NewErrMsg ( "您的钱包还有余额%.2f元,请先提现后再注销账号" ) , "用户钱包有余额,不能注销" , wallet . Balance )
}
if wallet . FrozenBalance > 0 {
return errors . Wrapf ( xerr . NewErrMsg ( "您的钱包还有冻结金额%.2f元,请等待解冻后再注销账号" ) , "用户钱包有冻结金额,不能注销" , wallet . FrozenBalance )
}
}
}
// 在事务中处理用户注销相关操作
err = l . svcCtx . UserModel . Trans ( l . ctx , func ( tranCtx context . Context , session sqlx . Session ) error {
// 1. 删除用户基本信息
if err := l . svcCtx . UserModel . Delete ( tranCtx , session , userID ) ; err != nil {
return errors . Wrapf ( err , "删除用户基本信息失败, userId: %d" , userID )
dbUser , err := l . svcCtx . UserModel . FindOne ( tranCtx , userID )
if err != nil {
return err
}
if dbUser . CancelledAt . Valid {
return xerr . NewErrCode ( xerr . USER_CANCELLED )
}
// 2. 查询并删除用户授权信息
UserAuthModelBuilder : = l . svcCtx . UserAuthModel . SelectBuilder ( ) . Where ( "user_id = ?" , userID )
userAuths , err : = l . svcCtx . UserAuthModel . FindAll ( tranCtx , UserAuthModelBuilder , "" )
dbUser . CancelledAt = sql . NullTime { Time : time . Now ( ) , Valid : true }
db User. Mobile = sq l. NullString { String : placeholderEnc , Valid : true }
dbUser . Nickname = sq l. NullString { String : "已注销用户" , Valid : true }
dbUser . Password = sql . NullString { Valid : false }
dbUser . Info = ""
if err := l . svcCtx . UserModel . UpdateWithVersion ( tranCtx , session , dbUser ) ; err != nil {
return pkgerrors . Wrapf ( err , "更新用户注销状态失败" )
}
authBuilder := l . svcCtx . UserAuthModel . SelectBuilder ( ) . Where ( "user_id = ?" , userID )
userAuths , err := l . svcCtx . UserAuthModel . FindAll ( tranCtx , authBuilder , "" )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询用户授权信息失败, userId: %d" , userID )
return pkg errors. Wrapf ( err , "查询用户授权失败" )
}
// 并发删除用户授权信息
if len ( userAuths ) > 0 {
funcs := make ( [ ] func ( ) error , len ( userAuths ) )
for i , userAuth := range userAuths {
authID := userAuth . Id
funcs [ i ] = func ( ) error {
return l . svcCtx . UserAuthModel . Delete ( tranCtx , session , authID )
}
}
if err := mr . Finish ( funcs ... ) ; err != nil {
return errors . Wrapf ( err , "删除用户授权信息失败" )
for _ , ua := range userAuths {
if err := l . svcCtx . UserAuthModel . Delete ( tranCtx , session , ua . Id ) ; err != nil {
return pkgerrors . Wrapf ( err , "删除用户授权失败 id=%d" , ua . Id )
}
}
// 3. 处理代理相关信息
if agentModel != nil {
// 3.1 删除代理信息
if err := l . svcCtx . AgentModel . Delete ( tranCtx , session , agentModel . Id ) ; err != nil {
return errors . Wrapf ( err , "删除代理信息失败, agentId: %d" , agentModel . Id )
}
// 3.2 查询并删除代理会员配置
configBuilder := l . svcCtx . AgentMembershipUserConfigModel . SelectBuilder ( ) . Where ( "agent_id = ?" , agentModel . Id )
configs , err := l . svcCtx . AgentMembershipUserConfigModel . FindAll ( tranCtx , configBuilder , "" )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询代理会员配置失败, agentId: %d" , agentModel . Id )
}
// 并发删除代理会员配置
if len ( configs ) > 0 {
configFuncs := make ( [ ] func ( ) error , len ( configs ) )
for i , config := range configs {
configId := config . Id
configFuncs [ i ] = func ( ) error {
return l . svcCtx . AgentMembershipUserConfigModel . Delete ( tranCtx , session , configId )
}
}
if err := mr . Finish ( configFuncs ... ) ; err != nil {
return errors . Wrapf ( err , "删除代理会员配置失败" )
}
}
// 3.3 删除代理钱包信息
wallet , err := l . svcCtx . AgentWalletModel . FindOneByAgentId ( tranCtx , agentModel . Id )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询代理钱包信息失败, agentId: %d" , agentModel . Id )
}
if wallet != nil {
if err := l . svcCtx . AgentWalletModel . Delete ( tranCtx , session , wallet . Id ) ; err != nil {
return errors . Wrapf ( err , "删除代理钱包信息失败, walletId: %d" , wallet . Id )
}
}
// 3.4 删除代理关系信息
closureBuilder := l . svcCtx . AgentClosureModel . SelectBuilder ( ) . Where ( "ancestor_id = ? AND depth = ?" , agentModel . Id , 1 )
closures , err := l . svcCtx . AgentClosureModel . FindAll ( tranCtx , closureBuilder , "" )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询代理关系信息失败, agentId: %d" , agentModel . Id )
}
if len ( closures ) > 0 {
closureFuncs := make ( [ ] func ( ) error , len ( closures ) )
for i , closure := range closures {
closureId := closure . Id
closureFuncs [ i ] = func ( ) error {
return l . svcCtx . AgentClosureModel . Delete ( tranCtx , session , closureId )
}
}
if err := mr . Finish ( closureFuncs ... ) ; err != nil {
return errors . Wrapf ( err , "删除代理关系信息失败" )
}
}
}
// 4. 查询并删除代理审核信息
auditBuilder := l . svcCtx . AgentAuditModel . SelectBuilder ( ) . Where ( "user_id = ?" , userID )
audits , err := l . svcCtx . AgentAuditModel . FindAll ( tranCtx , auditBuilder , "" )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询代理审核信息失败, userId: %d" , userID )
}
// 并发删除代理审核信息
if len ( audits ) > 0 {
auditFuncs := make ( [ ] func ( ) error , len ( audits ) )
for i , audit := range audits {
auditId := audit . Id
auditFuncs [ i ] = func ( ) error {
return l . svcCtx . AgentAuditModel . Delete ( tranCtx , session , auditId )
}
}
if err := mr . Finish ( auditFuncs ... ) ; err != nil {
return errors . Wrapf ( err , "删除代理审核信息失败" )
}
}
// 5. 删除用户查询记录
queryBuilder := l . svcCtx . QueryModel . SelectBuilder ( ) . Where ( "user_id = ?" , userID )
queries , err := l . svcCtx . QueryModel . FindAll ( tranCtx , queryBuilder , "" )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询用户查询记录失败, userId: %d" , userID )
return pkg errors. Wrapf ( err , "查询用户查询记录失败" )
}
if len ( q ueries ) > 0 {
queryFuncs := make ( [ ] func ( ) error , len ( queries ) )
for i , query := range queries {
queryId := query . Id
queryFuncs [ i ] = func ( ) error {
return l . svcCtx . QueryModel . Delete ( tranCtx , session , queryId )
}
}
if err := mr . Finish ( queryFuncs ... ) ; err != nil {
return errors . Wrapf ( err , "删除用户查询记录失败" )
for _ , q := range queries {
if err := l . svcCtx . Q ueryModel . Delete ( tranCtx , session , q . Id ) ; err != nil {
return pkgerrors . Wrapf ( err , "删除查询记录失败 id=%d" , q . Id )
}
}
// 6. 删除用户订单记录
orderBuilde r := l . svcCtx . Order Model. SelectBuilder ( ) . Where ( "user_id = ?" , userID )
orders , err : = l . svcCtx . OrderModel . FindAll ( tranCtx , orderBuilder , "" )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询用户订单记录失败, userId: %d" , userID )
}
if len ( orders ) > 0 {
orderFuncs := make ( [ ] func ( ) error , len ( orders ) )
for i , order := range orders {
orderId := order . Id
orderFuncs [ i ] = func ( ) error {
return l . svcCtx . OrderModel . Delete ( tranCtx , session , orderId )
}
if agentModel != nil {
ag , er r := l . svcCtx . Agent Model. FindOne ( tranCtx , agentModel . Id )
if err ! = nil {
return err
}
if err : = mr . Finish ( orderFuncs ... ) ; err != nil {
return errors . Wrapf ( err , "删除用户订单记录失败" )
ag . Mobile = placeholderEnc
ag . WechatId = sql . NullString { Valid : false }
if err := l . svcCtx . AgentModel . UpdateWithVersion ( tranCtx , session , ag ) ; err != nil {
return pkgerrors . Wrapf ( err , "更新代理占位信息失败" )
}
}
// 7. 删除代理订单信息
agentOrderBuilder := l . svcCtx . AgentOrderModel . SelectBuilder ( ) . Where ( "agent_id = ?" , agentModel . Id )
agentOrders , err := l . svcCtx . AgentOrderModel . FindAll ( tranCtx , agentOrderBuilder , "" )
if err != nil && ! errors . Is ( err , model . ErrNotFound ) {
return errors . Wrapf ( err , "查询代理订单信息失败, agentId: %d, err: %v" , agentModel . Id , err )
}
if len ( agentOrders ) > 0 {
agentOrderFuncs := make ( [ ] func ( ) error , len ( agentOrders ) )
for i , agentOrder := range agentOrders {
agentOrderId := agentOrder . Id
agentOrderFuncs [ i ] = func ( ) error {
return l . svcCtx . AgentOrderModel . Delete ( tranCtx , session , agentOrderId )
}
}
if err := mr . Finish ( agentOrderFuncs ... ) ; err != nil {
return errors . Wrapf ( err , "删除代理订单信息失败" )
}
}
return nil
} )
if err != nil {
return errors . Wrapf ( xerr . NewErrCode ( xerr . DB_ERROR ) , "用户注销失败%v" , err )
var ce * xerr . CodeError
if errors . As ( err , & ce ) {
return ce
}
return pkgerrors . Wrapf ( xerr . NewErrCode ( xerr . DB_ERROR ) , "用户注销失败: %v" , err )
}
return nil