package auth import ( "backend/internal/svc" "backend/internal/types" "backend/pkg/library/errs" "backend/pkg/library/errs/code" mb "backend/pkg/member/domain/member" member "backend/pkg/member/domain/usecase" "context" "time" "google.golang.org/protobuf/proto" "github.com/zeromicro/go-zero/core/logx" ) type RegisterLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } var PrepareFunc map[string]func(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error) = map[string]func(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error){ mb.Digimon.ToString(): buildCredentialsData, mb.Google.ToString(): buildGoogleData, mb.Line.ToString(): buildLineData, } // 註冊新帳號 func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic { return &RegisterLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *RegisterLogic) Register(req *types.LoginReq) (resp *types.LoginResp, err error) { // Step 1: 根據平台構建相關資料 var bd buildData switch req.AuthMethod { case "credentials": fn, ok := PrepareFunc[mb.Digimon.ToString()] if !ok { return nil, errs.InvalidRangeWithScope(code.CloudEPMember, 0, "failed to get correct credentials method") } bd, err = fn(l.ctx, req, l.svcCtx) if err != nil { return nil, err } case "platform": fn, ok := PrepareFunc[req.Platform.Provider] if !ok { return nil, errs.InvalidRangeWithScope(code.CloudEPMember, 0, "failed to get correct credentials method") } bd, err = fn(l.ctx, req, l.svcCtx) if err != nil { return nil, err } default: return nil, errs.InvalidFormatWithScope(code.CloudEPMember, "failed to get correct auth method") } // Step 2: 建立帳號 if err := l.svcCtx.AccountUC.CreateUserAccount(l.ctx, bd.CreateAccountReq); err != nil { return nil, err } // Step 3: 綁定帳號並獲取 UID account, err := l.svcCtx.AccountUC.BindAccount(l.ctx, bd.BindingUserReq) if err != nil { return nil, err } bd.CreateUserInfoRequest.UID = account.UID // Step 4: 更新使用者資訊 if err := l.svcCtx.AccountUC.BindUserInfo(l.ctx, bd.CreateUserInfoRequest); err != nil { return nil, err } // Step 5: 生成 Token req.LoginID = bd.CreateAccountReq.LoginID token, err := l.generateToken(req, account.UID) if err != nil { return nil, err } return &types.LoginResp{ UID: account.UID, AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, TokenType: token.TokenType, }, nil } type buildData struct { CreateAccountReq member.CreateLoginUserRequest BindingUserReq member.BindingUser CreateUserInfoRequest member.CreateUserInfoRequest } func buildCredentialsData(_ context.Context, req *types.LoginReq, _ *svc.ServiceContext) (buildData, error) { return buildData{ CreateAccountReq: member.CreateLoginUserRequest{ LoginID: req.LoginID, Token: req.Credentials.Password, Platform: mb.Digimon, }, BindingUserReq: member.BindingUser{ LoginID: req.LoginID, Type: mb.GetAccountTypeByCode(req.Credentials.AccountType), }, CreateUserInfoRequest: member.CreateUserInfoRequest{ AlarmCategory: mb.AlarmNoAlert, UserStatus: mb.AccountStatusUnverified, PreferredLanguage: mb.LangTW.ToString(), Currency: mb.CurrencyTWD.ToString(), }, }, nil } func buildGoogleData(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error) { googleToken, err := svc.AccountUC.VerifyGoogleAuthResult(ctx, member.VerifyAuthResultRequest{ Account: req.LoginID, Token: req.Platform.Token, }) if err != nil { return buildData{}, err } return buildData{ CreateAccountReq: member.CreateLoginUserRequest{ LoginID: googleToken.Email, Token: "", Platform: mb.Google, }, BindingUserReq: member.BindingUser{ LoginID: req.LoginID, Type: mb.AccountTypeNone, }, CreateUserInfoRequest: member.CreateUserInfoRequest{ AvatarURL: proto.String(googleToken.Picture), FullName: proto.String(googleToken.Name), Nickname: proto.String(googleToken.Name), Email: proto.String(googleToken.Email), AlarmCategory: mb.AlarmNoAlert, UserStatus: mb.AccountStatusUnverified, PreferredLanguage: mb.LangTW.ToString(), Currency: mb.CurrencyTWD.ToString(), }, }, nil } func buildLineData(ctx context.Context, req *types.LoginReq, svc *svc.ServiceContext) (buildData, error) { lineAccessToken, err := svc.AccountUC.LineCodeToAccessToken(ctx, req.LoginID) if err != nil { return buildData{}, err } userInfo, err := svc.AccountUC.LineGetProfileByAccessToken(ctx, lineAccessToken.AccessToken) if err != nil { return buildData{}, err } return buildData{ CreateAccountReq: member.CreateLoginUserRequest{ LoginID: userInfo.UserID, Token: "", Platform: mb.Line, }, BindingUserReq: member.BindingUser{ LoginID: userInfo.UserID, Type: mb.AccountTypeNone, }, CreateUserInfoRequest: member.CreateUserInfoRequest{ AvatarURL: proto.String(userInfo.PictureURL), FullName: proto.String(userInfo.DisplayName), Nickname: proto.String(userInfo.DisplayName), AlarmCategory: mb.AlarmNoAlert, UserStatus: mb.AccountStatusUnverified, PreferredLanguage: mb.LangTW.ToString(), Currency: mb.CurrencyTWD.ToString(), }, }, nil } type MockToken struct { AccessToken string `json:"access_token"` // 訪問令牌 TokenType string `json:"token_type"` // 令牌類型 ExpiresIn int64 `json:"expires_in"` // 過期時間(秒) RefreshToken string `json:"refresh_token"` // 刷新令牌 } // 生成 Token func (l *RegisterLogic) generateToken(req *types.LoginReq, uid string) (MockToken, error) { //credentials := tokenModule.ClientCredentials //role := "user" //if isTruHeartEmail(req.Account) { // role = "admin" //} // //return l.svcCtx.TokenUseCase.NewToken(l.ctx, tokenModule.AuthorizationReq{ // GrantType: credentials.ToString(), // DeviceID: req.DeviceID, // Scope: domain.DefaultScope, // IsRefreshToken: true, // Expires: time.Now().UTC().Add(l.svcCtx.Config.Token.Expired).Unix(), // Data: map[string]string{ // "uid": uid, // "role": role, // "account": req.Account, // }, // Role: role, //}) return MockToken{ AccessToken: "gg88g88", TokenType: "Bearer", ExpiresIn: time.Now().UTC().Add(100000000000).Unix(), RefreshToken: "gg88g88", }, nil }