2023-01-06 14:34:53 +08:00
|
|
|
package user_external_login
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
2023-01-06 17:22:09 +08:00
|
|
|
"github.com/answerdev/answer/internal/base/reason"
|
2023-01-06 14:34:53 +08:00
|
|
|
"github.com/answerdev/answer/internal/entity"
|
|
|
|
"github.com/answerdev/answer/internal/plugin"
|
|
|
|
"github.com/answerdev/answer/internal/schema"
|
|
|
|
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
2023-01-06 17:22:09 +08:00
|
|
|
"github.com/answerdev/answer/pkg/token"
|
|
|
|
"github.com/segmentfault/pacman/errors"
|
2023-01-06 14:34:53 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type UserExternalLoginRepo interface {
|
|
|
|
AddUserExternalLogin(ctx context.Context, user *entity.UserExternalLogin) (err error)
|
|
|
|
UpdateInfo(ctx context.Context, userInfo *entity.UserExternalLogin) (err error)
|
|
|
|
GetByExternalID(ctx context.Context, externalID string) (userInfo *entity.UserExternalLogin, exist bool, err error)
|
|
|
|
SetCacheUserExternalLoginInfo(
|
2023-01-06 17:22:09 +08:00
|
|
|
ctx context.Context, key string, info plugin.ExternalLoginUserInfo) (err error)
|
2023-01-06 14:34:53 +08:00
|
|
|
GetCacheUserExternalLoginInfo(
|
2023-01-06 17:22:09 +08:00
|
|
|
ctx context.Context, key string) (info plugin.ExternalLoginUserInfo, err error)
|
2023-01-06 14:34:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// UserExternalLoginService user external login service
|
|
|
|
type UserExternalLoginService struct {
|
|
|
|
userRepo usercommon.UserRepo
|
|
|
|
userExternalLoginRepo UserExternalLoginRepo
|
|
|
|
userCommonService *usercommon.UserCommon
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewUserExternalLoginService new user external login service
|
|
|
|
func NewUserExternalLoginService(
|
|
|
|
userRepo usercommon.UserRepo,
|
|
|
|
userCommonService *usercommon.UserCommon,
|
2023-01-06 14:48:41 +08:00
|
|
|
userExternalLoginRepo UserExternalLoginRepo,
|
2023-01-06 14:34:53 +08:00
|
|
|
) *UserExternalLoginService {
|
|
|
|
return &UserExternalLoginService{
|
2023-01-06 14:48:41 +08:00
|
|
|
userRepo: userRepo,
|
|
|
|
userCommonService: userCommonService,
|
|
|
|
userExternalLoginRepo: userExternalLoginRepo,
|
2023-01-06 14:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExternalLogin if user is already a member logged in
|
|
|
|
func (us *UserExternalLoginService) ExternalLogin(
|
2023-01-06 17:22:09 +08:00
|
|
|
ctx context.Context, externalUserInfo plugin.ExternalLoginUserInfo) (
|
2023-01-06 14:34:53 +08:00
|
|
|
resp *schema.UserExternalLoginResp, err error) {
|
|
|
|
// cache external user info, waiting for user enter email address.
|
|
|
|
if len(externalUserInfo.Email) == 0 {
|
2023-01-06 17:22:09 +08:00
|
|
|
bindingKey := token.GenerateToken()
|
|
|
|
err = us.userExternalLoginRepo.SetCacheUserExternalLoginInfo(ctx, bindingKey, externalUserInfo)
|
2023-01-06 14:34:53 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-06 17:22:09 +08:00
|
|
|
return &schema.UserExternalLoginResp{BindingKey: bindingKey}, nil
|
2023-01-06 14:34:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
oldUserInfo, exist, err := us.userRepo.GetByEmail(ctx, externalUserInfo.Email)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-06 14:48:41 +08:00
|
|
|
if !exist {
|
2023-01-06 17:22:09 +08:00
|
|
|
oldUserInfo, err = us.RegisterNewUser(ctx, externalUserInfo)
|
2023-01-06 14:48:41 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-06 14:34:53 +08:00
|
|
|
}
|
2023-01-06 17:22:09 +08:00
|
|
|
err = us.BindOldUser(ctx, externalUserInfo, oldUserInfo)
|
2023-01-06 14:34:53 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
|
|
|
ctx, oldUserInfo.ID, oldUserInfo.MailStatus, oldUserInfo.Status)
|
|
|
|
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
|
|
|
}
|
|
|
|
|
2023-01-06 17:22:09 +08:00
|
|
|
func (us *UserExternalLoginService) RegisterNewUser(ctx context.Context,
|
2023-01-06 14:34:53 +08:00
|
|
|
externalUserInfo plugin.ExternalLoginUserInfo) (userInfo *entity.User, err error) {
|
|
|
|
userInfo = &entity.User{}
|
|
|
|
userInfo.EMail = externalUserInfo.Email
|
|
|
|
userInfo.DisplayName = externalUserInfo.Name
|
|
|
|
userInfo.Username, err = us.userCommonService.MakeUsername(ctx, externalUserInfo.Name)
|
|
|
|
if err != nil {
|
|
|
|
userInfo.Username = "" // TODO random
|
|
|
|
}
|
|
|
|
userInfo.MailStatus = entity.EmailStatusToBeVerified
|
|
|
|
userInfo.Status = entity.UserStatusAvailable
|
|
|
|
userInfo.LastLoginDate = time.Now()
|
|
|
|
err = us.userRepo.AddUser(ctx, userInfo)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return userInfo, nil
|
|
|
|
}
|
|
|
|
|
2023-01-06 17:22:09 +08:00
|
|
|
func (us *UserExternalLoginService) BindOldUser(ctx context.Context,
|
2023-01-06 14:34:53 +08:00
|
|
|
externalUserInfo plugin.ExternalLoginUserInfo, oldUserInfo *entity.User) (err error) {
|
|
|
|
oldExternalUserInfo, exist, err := us.userExternalLoginRepo.GetByExternalID(ctx, externalUserInfo.ExternalID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if exist {
|
|
|
|
oldExternalUserInfo.MetaInfo = externalUserInfo.MetaInfo
|
|
|
|
oldExternalUserInfo.UserID = oldUserInfo.ID
|
|
|
|
err = us.userExternalLoginRepo.UpdateInfo(ctx, oldExternalUserInfo)
|
|
|
|
} else {
|
|
|
|
newExternalUserInfo := &entity.UserExternalLogin{
|
|
|
|
UserID: oldUserInfo.ID,
|
2023-01-06 17:22:09 +08:00
|
|
|
Provider: externalUserInfo.Provider,
|
2023-01-06 14:34:53 +08:00
|
|
|
ExternalID: externalUserInfo.ExternalID,
|
|
|
|
MetaInfo: externalUserInfo.MetaInfo,
|
|
|
|
}
|
|
|
|
err = us.userExternalLoginRepo.AddUserExternalLogin(ctx, newExternalUserInfo)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
2023-01-06 17:22:09 +08:00
|
|
|
|
|
|
|
func (us *UserExternalLoginService) ExternalLoginBindingUserSendEmail(
|
|
|
|
ctx context.Context, req *schema.ExternalLoginBindingUserSendEmailReq) (
|
|
|
|
resp *schema.ExternalLoginBindingUserSendEmailResp, err error) {
|
|
|
|
resp = &schema.ExternalLoginBindingUserSendEmailResp{}
|
|
|
|
externalLoginInfo, err := us.userExternalLoginRepo.GetCacheUserExternalLoginInfo(ctx, req.BindingKey)
|
|
|
|
if err != nil || len(externalLoginInfo.ExternalID) == 0 {
|
|
|
|
return nil, errors.BadRequest(reason.UserNotFound)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, exist, err := us.userRepo.GetByEmail(ctx, req.Email)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if exist && !req.Must {
|
|
|
|
resp.EmailExistAndMustBeConfirmed = true
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if !exist {
|
|
|
|
externalLoginInfo.Email = req.Email
|
|
|
|
_, err = us.RegisterNewUser(ctx, externalLoginInfo)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO send bind confirmation email
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (us *UserExternalLoginService) ExternalLoginBindingUser(
|
|
|
|
ctx context.Context, req *schema.ExternalLoginBindingUserReq) (
|
|
|
|
resp *schema.ExternalLoginBindingUserResp, err error) {
|
|
|
|
return
|
|
|
|
}
|