diff --git a/internal/db/models/user_dao.go b/internal/db/models/user_dao.go index 58ab2979..da31c5e6 100644 --- a/internal/db/models/user_dao.go +++ b/internal/db/models/user_dao.go @@ -104,7 +104,18 @@ func (this *UserDAO) FindUserFullname(tx *dbs.Tx, userId int64) (string, error) } // CreateUser 创建用户 -func (this *UserDAO) CreateUser(tx *dbs.Tx, username string, password string, fullname string, mobile string, tel string, email string, remark string, source string, clusterId int64) (int64, error) { +func (this *UserDAO) CreateUser(tx *dbs.Tx, username string, + password string, + fullname string, + mobile string, + tel string, + email string, + remark string, + source string, + clusterId int64, + features []string, + registeredIP string, + isVerified bool) (int64, error) { op := NewUserOperator() op.Username = username op.Password = stringutil.Md5(password) @@ -112,10 +123,24 @@ func (this *UserDAO) CreateUser(tx *dbs.Tx, username string, password string, fu op.Mobile = mobile op.Tel = tel op.Email = email + op.EmailIsVerified = false op.Remark = remark op.Source = source op.ClusterId = clusterId op.Day = timeutil.Format("Ymd") + op.IsVerified = isVerified + op.RegisteredIP = registeredIP + + // features + if len(features) == 0 { + op.Features = "[]" + } else { + featuresJSON, err := json.Marshal(features) + if err != nil { + return 0, err + } + op.Features = featuresJSON + } op.IsOn = true op.State = UserStateEnabled @@ -149,13 +174,15 @@ func (this *UserDAO) UpdateUser(tx *dbs.Tx, userId int64, username string, passw } // UpdateUserInfo 修改用户基本信息 -func (this *UserDAO) UpdateUserInfo(tx *dbs.Tx, userId int64, fullname string) error { +func (this *UserDAO) UpdateUserInfo(tx *dbs.Tx, userId int64, fullname string, mobile string, email string) error { if userId <= 0 { return errors.New("invalid userId") } op := NewUserOperator() op.Id = userId op.Fullname = fullname + op.Mobile = mobile + op.Email = email return this.Save(tx, op) } @@ -355,3 +382,16 @@ func (this *UserDAO) CountDailyUsers(tx *dbs.Tx, dayFrom string, dayTo string) ( return result, nil } + +// UpdateUserIsVerified 审核用户 +func (this *UserDAO) UpdateUserIsVerified(tx *dbs.Tx, userId int64, isRejected bool, rejectReason string) error { + if userId <= 0 { + return errors.New("invalid userId") + } + var op = NewUserOperator() + op.Id = userId + op.IsRejected = isRejected + op.RejectReason = rejectReason + op.IsVerified = true + return this.Save(tx, op) +} diff --git a/internal/db/models/user_model.go b/internal/db/models/user_model.go index b4741ecb..e559a005 100644 --- a/internal/db/models/user_model.go +++ b/internal/db/models/user_model.go @@ -2,43 +2,55 @@ package models // User 用户 type User struct { - Id uint32 `field:"id"` // ID - IsOn uint8 `field:"isOn"` // 是否启用 - Username string `field:"username"` // 用户名 - Password string `field:"password"` // 密码 - Fullname string `field:"fullname"` // 真实姓名 - Mobile string `field:"mobile"` // 手机号 - Tel string `field:"tel"` // 联系电话 - Remark string `field:"remark"` // 备注 - Email string `field:"email"` // 邮箱地址 - AvatarFileId uint64 `field:"avatarFileId"` // 头像文件ID - CreatedAt uint64 `field:"createdAt"` // 创建时间 - Day string `field:"day"` // YYYYMMDD - UpdatedAt uint64 `field:"updatedAt"` // 修改时间 - State uint8 `field:"state"` // 状态 - Source string `field:"source"` // 来源 - ClusterId uint32 `field:"clusterId"` // 集群ID - Features string `field:"features"` // 允许操作的特征 + Id uint32 `field:"id"` // ID + IsOn uint8 `field:"isOn"` // 是否启用 + Username string `field:"username"` // 用户名 + Password string `field:"password"` // 密码 + Fullname string `field:"fullname"` // 真实姓名 + Mobile string `field:"mobile"` // 手机号 + Tel string `field:"tel"` // 联系电话 + Remark string `field:"remark"` // 备注 + Email string `field:"email"` // 邮箱地址 + EmailIsVerified uint8 `field:"emailIsVerified"` // 邮箱是否已验证 + AvatarFileId uint64 `field:"avatarFileId"` // 头像文件ID + CreatedAt uint64 `field:"createdAt"` // 创建时间 + Day string `field:"day"` // YYYYMMDD + UpdatedAt uint64 `field:"updatedAt"` // 修改时间 + State uint8 `field:"state"` // 状态 + Source string `field:"source"` // 来源 + ClusterId uint32 `field:"clusterId"` // 集群ID + Features string `field:"features"` // 允许操作的特征 + RegisteredIP string `field:"registeredIP"` // 注册使用的IP + IsRejected uint8 `field:"isRejected"` // 是否已拒绝 + RejectReason string `field:"rejectReason"` // 拒绝理由 + IsVerified uint8 `field:"isVerified"` // 是否验证通过 + RequirePlans uint8 `field:"requirePlans"` // 是否需要购买套餐 } type UserOperator struct { - Id interface{} // ID - IsOn interface{} // 是否启用 - Username interface{} // 用户名 - Password interface{} // 密码 - Fullname interface{} // 真实姓名 - Mobile interface{} // 手机号 - Tel interface{} // 联系电话 - Remark interface{} // 备注 - Email interface{} // 邮箱地址 - AvatarFileId interface{} // 头像文件ID - CreatedAt interface{} // 创建时间 - Day interface{} // YYYYMMDD - UpdatedAt interface{} // 修改时间 - State interface{} // 状态 - Source interface{} // 来源 - ClusterId interface{} // 集群ID - Features interface{} // 允许操作的特征 + Id interface{} // ID + IsOn interface{} // 是否启用 + Username interface{} // 用户名 + Password interface{} // 密码 + Fullname interface{} // 真实姓名 + Mobile interface{} // 手机号 + Tel interface{} // 联系电话 + Remark interface{} // 备注 + Email interface{} // 邮箱地址 + EmailIsVerified interface{} // 邮箱是否已验证 + AvatarFileId interface{} // 头像文件ID + CreatedAt interface{} // 创建时间 + Day interface{} // YYYYMMDD + UpdatedAt interface{} // 修改时间 + State interface{} // 状态 + Source interface{} // 来源 + ClusterId interface{} // 集群ID + Features interface{} // 允许操作的特征 + RegisteredIP interface{} // 注册使用的IP + IsRejected interface{} // 是否已拒绝 + RejectReason interface{} // 拒绝理由 + IsVerified interface{} // 是否验证通过 + RequirePlans interface{} // 是否需要购买套餐 } func NewUserOperator() *UserOperator { diff --git a/internal/rpc/services/service_user.go b/internal/rpc/services/service_user.go index cfce8b86..f36ba61c 100644 --- a/internal/rpc/services/service_user.go +++ b/internal/rpc/services/service_user.go @@ -5,12 +5,15 @@ import ( "encoding/json" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" "github.com/TeaOSLab/EdgeAPI/internal/db/models" + "github.com/TeaOSLab/EdgeAPI/internal/errors" rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" + "github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/types" timeutil "github.com/iwind/TeaGo/utils/time" "time" @@ -30,13 +33,82 @@ func (this *UserService) CreateUser(ctx context.Context, req *pb.CreateUserReque tx := this.NullTx() - userId, err := models.SharedUserDAO.CreateUser(tx, req.Username, req.Password, req.Fullname, req.Mobile, req.Tel, req.Email, req.Remark, req.Source, req.NodeClusterId) + userId, err := models.SharedUserDAO.CreateUser(tx, req.Username, req.Password, req.Fullname, req.Mobile, req.Tel, req.Email, req.Remark, req.Source, req.NodeClusterId, nil, "", true) if err != nil { return nil, err } return &pb.CreateUserResponse{UserId: userId}, nil } +// RegisterUser 注册用户 +func (this *UserService) RegisterUser(ctx context.Context, req *pb.RegisterUserRequest) (*pb.RPCSuccess, error) { + userId, err := this.ValidateUserNode(ctx) + if err != nil { + return nil, err + } + + if userId > 0 { + return nil, this.PermissionError() + } + + // 注册配置 + configJSON, err := models.SharedSysSettingDAO.ReadSetting(nil, systemconfigs.SettingCodeUserRegisterConfig) + if err != nil { + return nil, err + } + if len(configJSON) == 0 { + return nil, errors.New("the registration has been disabled") + } + var config = userconfigs.DefaultUserRegisterConfig() + err = json.Unmarshal(configJSON, config) + if err != nil { + return nil, err + } + if !config.IsOn { + return nil, errors.New("the registration has been disabled") + } + + err = this.RunTx(func(tx *dbs.Tx) error { + // 检查用户名 + exists, err := models.SharedUserDAO.ExistUser(tx, 0, req.Username) + if err != nil { + return err + } + if exists { + return errors.New("the username exists already") + } + + // 创建用户 + _, err = models.SharedUserDAO.CreateUser(tx, req.Username, req.Password, req.Fullname, req.Mobile, "", req.Email, "", req.Source, config.ClusterId, config.Features, req.Ip, !config.RequireVerification) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + return this.Success() +} + +// VerifyUser 审核用户 +func (this *UserService) VerifyUser(ctx context.Context, req *pb.VerifyUserRequest) (*pb.RPCSuccess, error) { + _, err := this.ValidateAdmin(ctx, 0) + if err != nil { + return nil, err + } + + var tx = this.NullTx() + err = models.SharedUserDAO.UpdateUserIsVerified(tx, req.UserId, req.IsRejected, req.RejectReason) + if err != nil { + return nil, err + } + + return this.Success() +} + // UpdateUser 修改用户 func (this *UserService) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.RPCSuccess, error) { _, err := this.ValidateAdmin(ctx, 0) @@ -140,16 +212,19 @@ func (this *UserService) ListEnabledUsers(ctx context.Context, req *pb.ListEnabl } result = append(result, &pb.User{ - Id: int64(user.Id), - Username: user.Username, - Fullname: user.Fullname, - Mobile: user.Mobile, - Tel: user.Tel, - Email: user.Email, - Remark: user.Remark, - IsOn: user.IsOn == 1, - CreatedAt: int64(user.CreatedAt), - NodeCluster: pbCluster, + Id: int64(user.Id), + Username: user.Username, + Fullname: user.Fullname, + Mobile: user.Mobile, + Tel: user.Tel, + Email: user.Email, + Remark: user.Remark, + IsOn: user.IsOn == 1, + RegisteredIP: user.RegisteredIP, + IsVerified: user.IsVerified == 1, + IsRejected: user.IsRejected == 1, + CreatedAt: int64(user.CreatedAt), + NodeCluster: pbCluster, }) } @@ -187,16 +262,20 @@ func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnable } return &pb.FindEnabledUserResponse{User: &pb.User{ - Id: int64(user.Id), - Username: user.Username, - Fullname: user.Fullname, - Mobile: user.Mobile, - Tel: user.Tel, - Email: user.Email, - Remark: user.Remark, - IsOn: user.IsOn == 1, - CreatedAt: int64(user.CreatedAt), - NodeCluster: pbCluster, + Id: int64(user.Id), + Username: user.Username, + Fullname: user.Fullname, + Mobile: user.Mobile, + Tel: user.Tel, + Email: user.Email, + Remark: user.Remark, + IsOn: user.IsOn == 1, + CreatedAt: int64(user.CreatedAt), + RegisteredIP: user.RegisteredIP, + IsVerified: user.IsVerified == 1, + IsRejected: user.IsRejected == 1, + RejectReason: user.RejectReason, + NodeCluster: pbCluster, }}, nil } @@ -279,7 +358,7 @@ func (this *UserService) UpdateUserInfo(ctx context.Context, req *pb.UpdateUserI tx := this.NullTx() - err = models.SharedUserDAO.UpdateUserInfo(tx, req.UserId, req.Fullname) + err = models.SharedUserDAO.UpdateUserInfo(tx, req.UserId, req.Fullname, req.Mobile, req.Email) if err != nil { return nil, err }