243 lines
8.0 KiB
Go
243 lines
8.0 KiB
Go
package member
|
||
|
||
import (
|
||
bizDomain "biz-member-gateway/internal/domain"
|
||
|
||
"code.30cm.net/digimon/app-cloudep-member-server/pkg/domain/member"
|
||
|
||
memberUC "code.30cm.net/digimon/app-cloudep-member-server/pkg/domain/usecase"
|
||
tokenUC "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/usecase"
|
||
|
||
"time"
|
||
|
||
"code.30cm.net/digimon/library-go/errs"
|
||
"code.30cm.net/digimon/library-go/errs/code"
|
||
|
||
"context"
|
||
|
||
"github.com/golang/protobuf/proto"
|
||
|
||
"biz-member-gateway/internal/svc"
|
||
"biz-member-gateway/internal/types"
|
||
|
||
memberProto "code.30cm.net/digimon/proto-all/pkg/member"
|
||
permissionProto "code.30cm.net/digimon/proto-all/pkg/permission"
|
||
"github.com/zeromicro/go-zero/core/logx"
|
||
)
|
||
|
||
type AccountCreateLogic struct {
|
||
logx.Logger
|
||
ctx context.Context
|
||
svcCtx *svc.ServiceContext
|
||
}
|
||
|
||
// NewAccountCreateLogic 創建新會員
|
||
func NewAccountCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AccountCreateLogic {
|
||
return &AccountCreateLogic{
|
||
Logger: logx.WithContext(ctx),
|
||
ctx: ctx,
|
||
svcCtx: svcCtx,
|
||
}
|
||
}
|
||
|
||
// AccountCreate 建立新帳號 -> 業務邏輯
|
||
func (l *AccountCreateLogic) AccountCreate(req *types.CreateAccountRequest) (resp *types.LoginTokenResp, err error) {
|
||
platform := member.GetPlatformByPlatformCode(req.Platform)
|
||
if platform == member.PlatformNone {
|
||
// http 400
|
||
return nil, errs.InvalidFormat("platform not support")
|
||
}
|
||
|
||
// Step 1: 根據平台構建相關數據
|
||
createAccountReq, bindingUserReq, createUserInfoRequest, err := l.buildAccountRequests(req, platform)
|
||
if err != nil {
|
||
// 裡面有錯從 Grpc 已經轉換完成
|
||
return nil, err
|
||
}
|
||
|
||
// Step 2: 建立帳號
|
||
_, err = l.svcCtx.MemberRPC.CreateUserAccount(l.ctx, &memberProto.CreateLoginUserReq{
|
||
LoginId: createAccountReq.LoginID,
|
||
Token: createAccountReq.Token,
|
||
Platform: createAccountReq.Platform.ToInt64(),
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// Step 3: 綁定帳號並獲取 UID
|
||
account, err := l.svcCtx.MemberRPC.BindAccount(l.ctx, &memberProto.BindingUserReq{
|
||
LoginId: bindingUserReq.LoginID,
|
||
Type: int64(bindingUserReq.Type),
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// Step 4: 更新使用者資訊
|
||
_, err = l.svcCtx.MemberRPC.BindUserInfo(l.ctx, &memberProto.CreateUserInfoReq{
|
||
Uid: account.Uid,
|
||
AlarmType: memberProto.AlarmType(createUserInfoRequest.AlarmCategory),
|
||
Status: memberProto.MemberStatus(createUserInfoRequest.UserStatus),
|
||
Language: createUserInfoRequest.PreferredLanguage,
|
||
Currency: createUserInfoRequest.Currency,
|
||
Avatar: createUserInfoRequest.AvatarURL,
|
||
NickName: createUserInfoRequest.Nickname,
|
||
FullName: createUserInfoRequest.FullName,
|
||
Gender: createUserInfoRequest.GenderCode,
|
||
Birthdate: createUserInfoRequest.Birthdate,
|
||
PhoneNumber: createUserInfoRequest.PhoneNumber,
|
||
Email: createUserInfoRequest.Email,
|
||
Address: createUserInfoRequest.Address,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// TODO 綁定角色
|
||
|
||
// Step 5: 生成 Token
|
||
t, err := l.generateToken(req, account.GetUid())
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &types.LoginTokenResp{
|
||
UID: account.GetUid(),
|
||
AccessToken: t.AccessToken,
|
||
RefreshToken: t.RefreshToken,
|
||
TokenType: bizDomain.TokenTypeBearer,
|
||
}, nil
|
||
}
|
||
|
||
// 構建不同平台的請求數據
|
||
func (l *AccountCreateLogic) buildAccountRequests(req *types.CreateAccountRequest, platform member.Platform) (
|
||
memberUC.CreateLoginUserRequest, memberUC.BindingUser, memberUC.CreateUserInfoRequest, error) {
|
||
var createAccountReq memberUC.CreateLoginUserRequest
|
||
var bindingUserReq memberUC.BindingUser
|
||
var createUserInfoRequest memberUC.CreateUserInfoRequest
|
||
switch platform {
|
||
case member.Digimon:
|
||
// 驗證 Token 是否一致
|
||
if req.Token != req.TokenCheck {
|
||
return createAccountReq, bindingUserReq, createUserInfoRequest, errs.NewError(
|
||
code.CloudEPMember, code.InvalidRange, bizDomain.TokenNotTheSameAPIErrorCode,
|
||
"failed to verify check token",
|
||
)
|
||
}
|
||
createAccountReq = memberUC.CreateLoginUserRequest{
|
||
LoginID: req.Account,
|
||
Token: req.Token,
|
||
Platform: platform,
|
||
}
|
||
bindingUserReq = memberUC.BindingUser{
|
||
LoginID: req.Account,
|
||
Type: member.GetAccountTypeByCode(req.AccountType),
|
||
}
|
||
createUserInfoRequest = memberUC.CreateUserInfoRequest{
|
||
AlarmCategory: member.AlarmNoAlert,
|
||
UserStatus: member.AccountStatusUnverified,
|
||
PreferredLanguage: bizDomain.DefaultLang,
|
||
Currency: bizDomain.DefaultCurrency,
|
||
}
|
||
|
||
case member.Google:
|
||
googleToken, err := l.svcCtx.MemberRPC.VerifyGoogleAuthResult(l.ctx, &memberProto.VerifyAuthResultReq{
|
||
Account: proto.String(req.Account),
|
||
Token: req.Token,
|
||
})
|
||
if err != nil {
|
||
return createAccountReq, bindingUserReq, createUserInfoRequest, err
|
||
}
|
||
|
||
createAccountReq = memberUC.CreateLoginUserRequest{
|
||
LoginID: *googleToken.Email,
|
||
Token: "",
|
||
Platform: platform,
|
||
}
|
||
bindingUserReq = memberUC.BindingUser{
|
||
LoginID: *googleToken.Email,
|
||
Type: member.GetAccountTypeByCode(req.AccountType),
|
||
}
|
||
createUserInfoRequest = memberUC.CreateUserInfoRequest{
|
||
AvatarURL: googleToken.Picture,
|
||
FullName: googleToken.Name,
|
||
Nickname: googleToken.Name,
|
||
Email: googleToken.Email,
|
||
AlarmCategory: member.AlarmNoAlert,
|
||
UserStatus: member.AccountStatusActive,
|
||
PreferredLanguage: bizDomain.DefaultLang,
|
||
Currency: bizDomain.DefaultCurrency,
|
||
}
|
||
|
||
case member.Line:
|
||
// 用 code 換取 line access token
|
||
lineAccessToken, err := l.svcCtx.MemberRPC.LineCodeToAccessToken(l.ctx, &memberProto.LineGetTokenReq{
|
||
Code: req.Account,
|
||
})
|
||
if err != nil {
|
||
return createAccountReq, bindingUserReq, createUserInfoRequest, err
|
||
}
|
||
// 用 access token 換取 line 使用者資料
|
||
userInfo, err := l.svcCtx.MemberRPC.LineGetProfileByAccessToken(l.ctx, &memberProto.LineGetUserInfoReq{
|
||
Token: lineAccessToken.Token,
|
||
})
|
||
if err != nil {
|
||
return createAccountReq, bindingUserReq, createUserInfoRequest, err
|
||
}
|
||
|
||
createAccountReq = memberUC.CreateLoginUserRequest{
|
||
LoginID: userInfo.UserId,
|
||
Token: "",
|
||
Platform: platform,
|
||
}
|
||
bindingUserReq = memberUC.BindingUser{
|
||
LoginID: userInfo.UserId,
|
||
Type: member.GetAccountTypeByCode(req.AccountType),
|
||
}
|
||
|
||
createUserInfoRequest = memberUC.CreateUserInfoRequest{
|
||
AvatarURL: proto.String(userInfo.PictureUrl),
|
||
FullName: proto.String(userInfo.DisplayName),
|
||
Nickname: proto.String(userInfo.DisplayName),
|
||
AlarmCategory: member.AlarmNoAlert,
|
||
UserStatus: member.AccountStatusActive,
|
||
PreferredLanguage: bizDomain.DefaultLang,
|
||
Currency: bizDomain.DefaultCurrency,
|
||
}
|
||
case member.PlatformNone:
|
||
default:
|
||
return createAccountReq, bindingUserReq, createUserInfoRequest, errs.InvalidFormat("invalid platform")
|
||
}
|
||
|
||
return createAccountReq, bindingUserReq, createUserInfoRequest, nil
|
||
}
|
||
|
||
// 生成 Token 這裡是註冊的,所以角色是固定的,不能讓平常註冊的使用者選擇角色
|
||
func (l *AccountCreateLogic) generateToken(req *types.CreateAccountRequest, uid string) (tokenUC.AccessTokenResponse, error) {
|
||
credentials := "client_credentials"
|
||
// 生成預設的Role -> 所有邏輯上的其他角色,應該都要從 user 開始,後續再通過admin 做更改
|
||
// 第一個 admin 應該是直接插入資料庫的
|
||
t, err := l.svcCtx.TokenRPC.NewToken(l.ctx, &permissionProto.AuthorizationReq{
|
||
GrantType: credentials,
|
||
DeviceId: req.DeviceID,
|
||
Scope: bizDomain.DefaultRole,
|
||
IsRefreshToken: true,
|
||
Account: req.Account,
|
||
Uid: uid,
|
||
Expires: proto.Int64(time.Now().UTC().Add(l.svcCtx.Config.Token.Expired).UnixNano()), // 指定到期的時間
|
||
RefreshExpire: proto.Int64(time.Now().UTC().Add(l.svcCtx.Config.Token.RefreshExpired).UnixNano()), // 指定到期的時間
|
||
Data: map[string]string{},
|
||
Role: bizDomain.DefaultRole,
|
||
})
|
||
if err != nil {
|
||
return tokenUC.AccessTokenResponse{}, errs.FromGRPCError(err)
|
||
}
|
||
|
||
return tokenUC.AccessTokenResponse{
|
||
AccessToken: t.AccessToken,
|
||
ExpiresIn: t.ExpiresIn,
|
||
RefreshToken: t.RefreshToken,
|
||
}, nil
|
||
}
|