Initial commit (code only without large binaries)
This commit is contained in:
900
EdgeAPI/internal/rpc/services/users/service_user.go
Normal file
900
EdgeAPI/internal/rpc/services/users/service_user.go
Normal file
@@ -0,0 +1,900 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||||
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/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UserService 用户相关服务
|
||||
type UserService struct {
|
||||
services.BaseService
|
||||
}
|
||||
|
||||
// CreateUser 创建用户
|
||||
func (this *UserService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var 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, nil, "", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.CreateUserResponse{UserId: userId}, nil
|
||||
}
|
||||
|
||||
// VerifyUser 审核用户
|
||||
func (this *UserService) VerifyUser(ctx context.Context, req *pb.VerifyUserRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
oldClusterId, err := models.SharedUserDAO.FindUserClusterId(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = models.SharedUserDAO.UpdateUser(tx, req.UserId, req.Username, req.Password, req.Fullname, req.Mobile, req.Tel, req.Email, req.Remark, req.IsOn, req.NodeClusterId, req.BandwidthAlgo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if oldClusterId != req.NodeClusterId {
|
||||
err = models.SharedServerDAO.UpdateUserServersClusterId(tx, req.UserId, oldClusterId, req.NodeClusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// DeleteUser 删除用户
|
||||
func (this *UserService) DeleteUser(ctx context.Context, req *pb.DeleteUserRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 删除其下的Server
|
||||
serverIds, err := models.SharedServerDAO.FindAllEnabledServerIdsWithUserId(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, serverId := range serverIds {
|
||||
err := models.SharedServerDAO.DisableServer(tx, serverId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = models.SharedUserDAO.DisableUser(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// CountAllEnabledUsers 计算用户数量
|
||||
func (this *UserService) CountAllEnabledUsers(ctx context.Context, req *pb.CountAllEnabledUsersRequest) (*pb.RPCCountResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
count, err := models.SharedUserDAO.CountAllEnabledUsers(tx, 0, req.Keyword, req.IsVerifying, req.MobileIsVerified)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// ListEnabledUsers 列出单页用户
|
||||
func (this *UserService) ListEnabledUsers(ctx context.Context, req *pb.ListEnabledUsersRequest) (*pb.ListEnabledUsersResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
users, err := models.SharedUserDAO.ListEnabledUsers(tx, 0, req.Keyword, req.IsVerifying, req.MobileIsVerified, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*pb.User{}
|
||||
for _, user := range users {
|
||||
// 集群信息
|
||||
var pbCluster *pb.NodeCluster = nil
|
||||
if user.ClusterId > 0 {
|
||||
clusterName, err := models.SharedNodeClusterDAO.FindNodeClusterName(tx, int64(user.ClusterId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pbCluster = &pb.NodeCluster{
|
||||
Id: int64(user.ClusterId),
|
||||
Name: clusterName,
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, &pb.User{
|
||||
Id: int64(user.Id),
|
||||
Username: user.Username,
|
||||
Fullname: user.Fullname,
|
||||
Mobile: user.Mobile,
|
||||
VerifiedMobile: user.VerifiedMobile,
|
||||
Tel: user.Tel,
|
||||
Email: user.Email,
|
||||
Remark: user.Remark,
|
||||
IsOn: user.IsOn,
|
||||
RegisteredIP: user.RegisteredIP,
|
||||
IsVerified: user.IsVerified,
|
||||
IsRejected: user.IsRejected,
|
||||
CreatedAt: int64(user.CreatedAt),
|
||||
NodeCluster: pbCluster,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListEnabledUsersResponse{Users: result}, nil
|
||||
}
|
||||
|
||||
// FindEnabledUser 查询单个用户信息
|
||||
func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnabledUserRequest) (*pb.FindEnabledUserResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
user, err := models.SharedUserDAO.FindEnabledUser(tx, req.UserId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return &pb.FindEnabledUserResponse{User: nil}, nil
|
||||
}
|
||||
|
||||
// 集群信息
|
||||
var pbCluster *pb.NodeCluster = nil
|
||||
if user.ClusterId > 0 {
|
||||
clusterName, err := models.SharedNodeClusterDAO.FindNodeClusterName(tx, int64(user.ClusterId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pbCluster = &pb.NodeCluster{
|
||||
Id: int64(user.ClusterId),
|
||||
Name: clusterName,
|
||||
}
|
||||
}
|
||||
|
||||
// 认证信息
|
||||
isIndividualIdentified, err := models.SharedUserIdentityDAO.CheckUserIdentityIsVerified(tx, req.UserId, userconfigs.UserIdentityOrgTypeIndividual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isEnterpriseIdentified, err := models.SharedUserIdentityDAO.CheckUserIdentityIsVerified(tx, req.UserId, userconfigs.UserIdentityOrgTypeEnterprise)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// OTP认证
|
||||
var pbOtpAuth *pb.Login = nil
|
||||
{
|
||||
userAuth, err := models.SharedLoginDAO.FindEnabledLoginWithType(tx, 0, req.UserId, models.LoginTypeOTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userAuth != nil {
|
||||
pbOtpAuth = &pb.Login{
|
||||
Id: int64(userAuth.Id),
|
||||
Type: userAuth.Type,
|
||||
ParamsJSON: userAuth.Params,
|
||||
IsOn: userAuth.IsOn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
VerifiedEmail: user.VerifiedEmail,
|
||||
VerifiedMobile: user.VerifiedMobile,
|
||||
Remark: user.Remark,
|
||||
IsOn: user.IsOn,
|
||||
CreatedAt: int64(user.CreatedAt),
|
||||
RegisteredIP: user.RegisteredIP,
|
||||
IsVerified: user.IsVerified,
|
||||
IsRejected: user.IsRejected,
|
||||
RejectReason: user.RejectReason,
|
||||
NodeCluster: pbCluster,
|
||||
IsIndividualIdentified: isIndividualIdentified,
|
||||
IsEnterpriseIdentified: isEnterpriseIdentified,
|
||||
BandwidthAlgo: user.BandwidthAlgo,
|
||||
OtpLogin: pbOtpAuth,
|
||||
Lang: user.Lang,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CheckUserUsername 检查用户名是否存在
|
||||
func (this *UserService) CheckUserUsername(ctx context.Context, req *pb.CheckUserUsernameRequest) (*pb.CheckUserUsernameResponse, error) {
|
||||
userType, _, userId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 校验权限
|
||||
if userType == rpcutils.UserTypeUser && userId != req.UserId {
|
||||
return nil, this.PermissionError()
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
b, err := models.SharedUserDAO.ExistUser(tx, req.UserId, req.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.CheckUserUsernameResponse{Exists: b}, nil
|
||||
}
|
||||
|
||||
// LoginUser 登录
|
||||
func (this *UserService) LoginUser(ctx context.Context, req *pb.LoginUserRequest) (*pb.LoginUserResponse, error) {
|
||||
_, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
// 允许管理员调用此接口
|
||||
_, err = this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !teaconst.IsPlus {
|
||||
return &pb.LoginUserResponse{
|
||||
UserId: 0,
|
||||
IsOk: false,
|
||||
Message: "你正在使用的系统版本为非商业版本或已过期,请管理员续费后才能登录",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if len(req.Username) == 0 || len(req.Password) == 0 {
|
||||
return &pb.LoginUserResponse{
|
||||
UserId: 0,
|
||||
IsOk: false,
|
||||
Message: "请输入正确的用户名密码",
|
||||
}, nil
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 邮箱登录
|
||||
var registerConfig *userconfigs.UserRegisterConfig
|
||||
if strings.Contains(req.Username, "@") {
|
||||
// 是否允许
|
||||
if registerConfig == nil {
|
||||
registerConfig, err = models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if registerConfig != nil && registerConfig.EmailVerification.CanLogin {
|
||||
userId, err := models.SharedUserDAO.CheckUserEmailPassword(tx, req.Username, req.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId > 0 {
|
||||
return &pb.LoginUserResponse{
|
||||
UserId: userId,
|
||||
IsOk: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 手机号登录
|
||||
if utils.IsValidMobile(req.Username) {
|
||||
// 是否允许
|
||||
if registerConfig == nil {
|
||||
registerConfig, err = models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if registerConfig != nil && registerConfig.MobileVerification.CanLogin {
|
||||
userId, err := models.SharedUserDAO.CheckUserMobilePassword(tx, req.Username, req.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId > 0 {
|
||||
return &pb.LoginUserResponse{
|
||||
UserId: userId,
|
||||
IsOk: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 用户名登录
|
||||
userId, err := models.SharedUserDAO.CheckUserPassword(tx, req.Username, req.Password)
|
||||
if err != nil {
|
||||
utils.PrintError(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId <= 0 {
|
||||
return &pb.LoginUserResponse{
|
||||
UserId: 0,
|
||||
IsOk: false,
|
||||
Message: "请输入正确的用户名密码",
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &pb.LoginUserResponse{
|
||||
UserId: userId,
|
||||
IsOk: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateUserInfo 修改用户基本信息
|
||||
func (this *UserService) UpdateUserInfo(ctx context.Context, req *pb.UpdateUserInfoRequest) (*pb.RPCSuccess, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId != req.UserId {
|
||||
return nil, this.PermissionError()
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedUserDAO.UpdateUserInfo(tx, req.UserId, req.Fullname, req.Mobile, req.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// UpdateUserLogin 修改用户登录信息
|
||||
func (this *UserService) UpdateUserLogin(ctx context.Context, req *pb.UpdateUserLoginRequest) (*pb.RPCSuccess, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId != req.UserId {
|
||||
return nil, this.PermissionError()
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedUserDAO.UpdateUserLogin(tx, req.UserId, req.Username, req.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// ComposeUserDashboard 取得用户Dashboard数据
|
||||
func (this *UserService) ComposeUserDashboard(ctx context.Context, req *pb.ComposeUserDashboardRequest) (*pb.ComposeUserDashboardResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
bandwidthAglo, err := models.SharedUserDAO.FindUserBandwidthAlgoForView(tx, req.UserId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 网站数量
|
||||
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", req.UserId, 0, configutils.BoolStateAll, []string{}, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 时间相关
|
||||
var currentMonth = timeutil.Format("Ym")
|
||||
var currentDay = timeutil.Format("Ymd")
|
||||
|
||||
// 本月总流量
|
||||
monthlyTrafficBytes, err := models.SharedUserBandwidthStatDAO.SumUserMonthly(tx, req.UserId, currentMonth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 本月带宽峰值
|
||||
var monthlyPeekBandwidthBytes int64 = 0
|
||||
{
|
||||
stat, err := models.SharedUserBandwidthStatDAO.FindUserPeekBandwidthInMonth(tx, req.UserId, currentMonth, bandwidthAglo == systemconfigs.BandwidthAlgoAvg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stat != nil {
|
||||
monthlyPeekBandwidthBytes = int64(stat.Bytes)
|
||||
}
|
||||
}
|
||||
|
||||
// 本日带宽峰值
|
||||
var dailyPeekBandwidthBytes int64 = 0
|
||||
{
|
||||
stat, err := models.SharedUserBandwidthStatDAO.FindUserPeekBandwidthInDay(tx, req.UserId, currentDay, bandwidthAglo == systemconfigs.BandwidthAlgoAvg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stat != nil {
|
||||
dailyPeekBandwidthBytes = int64(stat.Bytes)
|
||||
}
|
||||
}
|
||||
|
||||
// 今日总流量
|
||||
dailyTrafficStat, err := models.SharedUserBandwidthStatDAO.SumUserDaily(tx, req.UserId, 0, currentDay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dailyTrafficStat == nil {
|
||||
dailyTrafficStat = &models.UserBandwidthStat{}
|
||||
}
|
||||
|
||||
// 近 30 日流量带宽趋势
|
||||
var dailyTrafficStats = []*pb.ComposeUserDashboardResponse_DailyTrafficStat{}
|
||||
var dailyPeekBandwidthStats = []*pb.ComposeUserDashboardResponse_DailyPeekBandwidthStat{}
|
||||
|
||||
var dayFrom = ""
|
||||
var dayTo = ""
|
||||
for i := 30; i >= 0; i-- {
|
||||
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -i))
|
||||
if len(dayFrom) == 0 {
|
||||
dayFrom = day
|
||||
}
|
||||
if len(dayTo) == 0 || day > dayTo {
|
||||
dayTo = day
|
||||
}
|
||||
|
||||
// 流量
|
||||
trafficStat, err := models.SharedUserBandwidthStatDAO.SumUserDaily(tx, req.UserId, 0, day)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if trafficStat == nil {
|
||||
trafficStat = &models.UserBandwidthStat{}
|
||||
}
|
||||
|
||||
// 峰值带宽
|
||||
peekBandwidthBytesStat, err := models.SharedUserBandwidthStatDAO.FindUserPeekBandwidthInDay(tx, req.UserId, day, bandwidthAglo == systemconfigs.BandwidthAlgoAvg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var peekBandwidthBytes int64 = 0
|
||||
if peekBandwidthBytesStat != nil {
|
||||
peekBandwidthBytes = int64(peekBandwidthBytesStat.Bytes)
|
||||
}
|
||||
|
||||
dailyTrafficStats = append(dailyTrafficStats, &pb.ComposeUserDashboardResponse_DailyTrafficStat{
|
||||
Day: day,
|
||||
Bytes: int64(trafficStat.TotalBytes),
|
||||
CachedBytes: int64(trafficStat.CachedBytes),
|
||||
AttackBytes: int64(trafficStat.AttackBytes),
|
||||
CountRequests: int64(trafficStat.CountRequests),
|
||||
CountCachedRequests: int64(trafficStat.CountCachedRequests),
|
||||
CountAttackRequests: int64(trafficStat.CountAttackRequests),
|
||||
})
|
||||
dailyPeekBandwidthStats = append(dailyPeekBandwidthStats, &pb.ComposeUserDashboardResponse_DailyPeekBandwidthStat{Day: day, Bytes: peekBandwidthBytes})
|
||||
}
|
||||
var result = &pb.ComposeUserDashboardResponse{
|
||||
CountServers: countServers,
|
||||
MonthlyTrafficBytes: monthlyTrafficBytes,
|
||||
MonthlyPeekBandwidthBytes: monthlyPeekBandwidthBytes,
|
||||
DailyTrafficBytes: int64(dailyTrafficStat.TotalBytes),
|
||||
DailyPeekBandwidthBytes: dailyPeekBandwidthBytes,
|
||||
DailyTrafficStats: dailyTrafficStats,
|
||||
DailyPeekBandwidthStats: dailyPeekBandwidthStats,
|
||||
}
|
||||
|
||||
// 带宽百分位
|
||||
var bandwidthPercentile = systemconfigs.DefaultBandwidthPercentile
|
||||
userConfig, _ := models.SharedSysSettingDAO.ReadUserUIConfig(tx)
|
||||
if userConfig != nil && userConfig.TrafficStats.BandwidthPercentile > 0 {
|
||||
bandwidthPercentile = userConfig.TrafficStats.BandwidthPercentile
|
||||
}
|
||||
result.BandwidthPercentile = bandwidthPercentile
|
||||
stat, err := models.SharedUserBandwidthStatDAO.FindPercentileBetweenDays(tx, req.UserId, 0, dayFrom, dayTo, bandwidthPercentile, bandwidthAglo == systemconfigs.BandwidthAlgoAvg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stat != nil {
|
||||
result.BandwidthPercentileBits = int64(stat.Bytes) * 8
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindUserNodeClusterId 获取用户所在的集群ID
|
||||
func (this *UserService) FindUserNodeClusterId(ctx context.Context, req *pb.FindUserNodeClusterIdRequest) (*pb.FindUserNodeClusterIdResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
clusterId, err := models.SharedUserDAO.FindUserClusterId(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.FindUserNodeClusterIdResponse{NodeClusterId: clusterId}, nil
|
||||
}
|
||||
|
||||
// UpdateUserFeatures 设置用户能使用的功能
|
||||
func (this *UserService) UpdateUserFeatures(ctx context.Context, req *pb.UpdateUserFeaturesRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
featuresJSON, err := json.Marshal(req.FeatureCodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedUserDAO.UpdateUserFeatures(tx, req.UserId, featuresJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// UpdateAllUsersFeatures 设置所有用户能使用的功能
|
||||
func (this *UserService) UpdateAllUsersFeatures(ctx context.Context, req *pb.UpdateAllUsersFeaturesRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
err = models.SharedUserDAO.UpdateUsersFeatures(tx, req.FeatureCodes, req.Overwrite)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindAllUserFeatureDefinitions 获取所有的功能定义
|
||||
func (this *UserService) FindAllUserFeatureDefinitions(ctx context.Context, req *pb.FindAllUserFeatureDefinitionsRequest) (*pb.FindAllUserFeatureDefinitionsResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var features = userconfigs.FindAllUserFeatures()
|
||||
var result = []*pb.UserFeature{}
|
||||
for _, feature := range features {
|
||||
result = append(result, feature.ToPB())
|
||||
}
|
||||
return &pb.FindAllUserFeatureDefinitionsResponse{Features: result}, nil
|
||||
}
|
||||
|
||||
// ComposeUserGlobalBoard 组合全局的看板数据
|
||||
func (this *UserService) ComposeUserGlobalBoard(ctx context.Context, req *pb.ComposeUserGlobalBoardRequest) (*pb.ComposeUserGlobalBoardResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result = &pb.ComposeUserGlobalBoardResponse{}
|
||||
var tx = this.NullTx()
|
||||
totalUsers, err := models.SharedUserDAO.CountAllEnabledUsers(tx, 0, "", false, -1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.TotalUsers = totalUsers
|
||||
|
||||
// 等待审核的用户
|
||||
countVerifyingUsers, err := models.SharedUserDAO.CountAllVerifyingUsers(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.CountVerifyingUsers = countVerifyingUsers
|
||||
|
||||
countTodayUsers, err := models.SharedUserDAO.SumDailyUsers(tx, timeutil.Format("Ymd"), timeutil.Format("Ymd"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.CountTodayUsers = countTodayUsers
|
||||
|
||||
{
|
||||
w := types.Int(timeutil.Format("w"))
|
||||
if w == 0 {
|
||||
w = 7
|
||||
}
|
||||
weekFrom := time.Now().AddDate(0, 0, -w+1)
|
||||
dayFrom := timeutil.Format("Ymd", weekFrom)
|
||||
dayTo := timeutil.Format("Ymd", weekFrom.AddDate(0, 0, 6))
|
||||
countWeeklyUsers, err := models.SharedUserDAO.SumDailyUsers(tx, dayFrom, dayTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.CountWeeklyUsers = countWeeklyUsers
|
||||
}
|
||||
|
||||
// 用户节点数量
|
||||
countUserNodes, err := models.SharedUserNodeDAO.CountAllEnabledUserNodes(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.CountUserNodes = countUserNodes
|
||||
|
||||
// 离线用户节点
|
||||
countOfflineUserNodes, err := models.SharedUserNodeDAO.CountAllEnabledAndOnOfflineNodes(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.CountOfflineUserNodes = countOfflineUserNodes
|
||||
|
||||
// 用户增长趋势
|
||||
dayFrom := timeutil.Format("Ymd", time.Now().AddDate(0, 0, -14))
|
||||
dayStats, err := models.SharedUserDAO.CountDailyUsers(tx, dayFrom, timeutil.Format("Ymd"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.DailyStats = dayStats
|
||||
|
||||
// CPU、内存、负载
|
||||
cpuValues, err := models.SharedNodeValueDAO.ListValuesForUserNodes(tx, nodeconfigs.NodeValueItemCPU, "usage", nodeconfigs.NodeValueRangeMinute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range cpuValues {
|
||||
result.CpuNodeValues = append(result.CpuNodeValues, &pb.NodeValue{
|
||||
ValueJSON: v.Value,
|
||||
CreatedAt: int64(v.CreatedAt),
|
||||
})
|
||||
}
|
||||
|
||||
memoryValues, err := models.SharedNodeValueDAO.ListValuesForUserNodes(tx, nodeconfigs.NodeValueItemMemory, "usage", nodeconfigs.NodeValueRangeMinute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range memoryValues {
|
||||
result.MemoryNodeValues = append(result.MemoryNodeValues, &pb.NodeValue{
|
||||
ValueJSON: v.Value,
|
||||
CreatedAt: int64(v.CreatedAt),
|
||||
})
|
||||
}
|
||||
|
||||
loadValues, err := models.SharedNodeValueDAO.ListValuesForUserNodes(tx, nodeconfigs.NodeValueItemLoad, "load1m", nodeconfigs.NodeValueRangeMinute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range loadValues {
|
||||
result.LoadNodeValues = append(result.LoadNodeValues, &pb.NodeValue{
|
||||
ValueJSON: v.Value,
|
||||
CreatedAt: int64(v.CreatedAt),
|
||||
})
|
||||
}
|
||||
|
||||
// 流量排行
|
||||
var hourFrom = timeutil.Format("YmdH", time.Now().Add(-23*time.Hour))
|
||||
var hourTo = timeutil.Format("YmdH")
|
||||
topUserStats, err := models.SharedServerDailyStatDAO.FindTopUserStats(tx, hourFrom, hourTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, stat := range topUserStats {
|
||||
userName, err := models.SharedUserDAO.FindUserFullname(tx, int64(stat.UserId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.TopTrafficStats = append(result.TopTrafficStats, &pb.ComposeUserGlobalBoardResponse_TrafficStat{
|
||||
UserId: int64(stat.UserId),
|
||||
UserName: userName,
|
||||
CountRequests: int64(stat.CountRequests),
|
||||
Bytes: int64(stat.Bytes),
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CheckUserOTPWithUsername 检查是否需要输入OTP
|
||||
func (this *UserService) CheckUserOTPWithUsername(ctx context.Context, req *pb.CheckUserOTPWithUsernameRequest) (*pb.CheckUserOTPWithUsernameResponse, error) {
|
||||
_, err := this.ValidateUserNode(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(req.Username) == 0 {
|
||||
return &pb.CheckUserOTPWithUsernameResponse{RequireOTP: false}, nil
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
userId, err := models.SharedUserDAO.FindEnabledUserIdWithUsername(tx, req.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId <= 0 {
|
||||
return &pb.CheckUserOTPWithUsernameResponse{RequireOTP: false}, nil
|
||||
}
|
||||
|
||||
otpIsOn, err := models.SharedLoginDAO.CheckLoginIsOn(tx, 0, userId, "otp")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.CheckUserOTPWithUsernameResponse{RequireOTP: otpIsOn}, nil
|
||||
}
|
||||
|
||||
// CheckUserServersState 检查用户服务可用状态
|
||||
func (this *UserService) CheckUserServersState(ctx context.Context, req *pb.CheckUserServersStateRequest) (*pb.CheckUserServersStateResponse, error) {
|
||||
_, err := this.ValidateNode(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
isEnabled, err := models.SharedUserDAO.CheckUserServersEnabled(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.CheckUserServersStateResponse{
|
||||
IsEnabled: isEnabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RenewUserServersState 更新用户服务可用状态
|
||||
func (this *UserService) RenewUserServersState(ctx context.Context, req *pb.RenewUserServersStateRequest) (*pb.RenewUserServersStateResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
isEnabled, err := models.SharedUserDAO.RenewUserServersState(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.RenewUserServersStateResponse{
|
||||
IsEnabled: isEnabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CheckUserEmail 检查邮箱是否被使用
|
||||
func (this *UserService) CheckUserEmail(ctx context.Context, req *pb.CheckUserEmailRequest) (*pb.CheckUserEmailResponse, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(req.Email) == 0 {
|
||||
return nil, errors.New("'email' required")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
emailOwnerUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedEmail(tx, req.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if emailOwnerUserId > 0 && userId != emailOwnerUserId {
|
||||
return &pb.CheckUserEmailResponse{Exists: true}, nil
|
||||
}
|
||||
return &pb.CheckUserEmailResponse{Exists: false}, nil
|
||||
}
|
||||
|
||||
// CheckUserMobile 检查手机号码是否被使用
|
||||
func (this *UserService) CheckUserMobile(ctx context.Context, req *pb.CheckUserMobileRequest) (*pb.CheckUserMobileResponse, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(req.Mobile) == 0 {
|
||||
return nil, errors.New("'mobile' required")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
mobileOwnerUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedMobile(tx, req.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mobileOwnerUserId > 0 && userId != mobileOwnerUserId {
|
||||
return &pb.CheckUserMobileResponse{Exists: true}, nil
|
||||
}
|
||||
return &pb.CheckUserMobileResponse{Exists: false}, nil
|
||||
}
|
||||
|
||||
// FindUserVerifiedEmailWithUsername 根据用户名查询用户绑定的邮箱
|
||||
func (this *UserService) FindUserVerifiedEmailWithUsername(ctx context.Context, req *pb.FindUserVerifiedEmailWithUsernameRequest) (*pb.FindUserVerifiedEmailWithUsernameResponse, error) {
|
||||
_, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
userId, err := models.SharedUserDAO.FindEnabledUserIdWithUsername(tx, req.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId <= 0 {
|
||||
return &pb.FindUserVerifiedEmailWithUsernameResponse{
|
||||
Email: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
email, err := models.SharedUserDAO.FindUserVerifiedEmail(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.FindUserVerifiedEmailWithUsernameResponse{
|
||||
Email: email,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"net/mail"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserEmailVerificationService struct {
|
||||
services.BaseService
|
||||
}
|
||||
|
||||
// VerifyUserEmail 认证邮箱
|
||||
func (this *UserEmailVerificationService) VerifyUserEmail(ctx context.Context, req *pb.VerifyUserEmailRequest) (*pb.VerifyUserEmailResponse, error) {
|
||||
_, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(req.Code) == 0 {
|
||||
return nil, errors.New("'code' should not be empty")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
verification, err := models.SharedUserEmailVerificationDAO.FindVerificationWithCode(tx, req.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if verification == nil {
|
||||
return &pb.VerifyUserEmailResponse{
|
||||
UserId: 0,
|
||||
Email: "",
|
||||
ErrorCode: "WRONG_CODE",
|
||||
ErrorMessage: "激活码错误或已过期",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 邮箱是否已被别的用户所激活
|
||||
emailUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedEmail(tx, verification.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if emailUserId > 0 && emailUserId != int64(verification.UserId) {
|
||||
return &pb.VerifyUserEmailResponse{
|
||||
UserId: 0,
|
||||
Email: verification.Email,
|
||||
ErrorCode: "VERIFIED_EMAIL",
|
||||
ErrorMessage: "此邮箱已经被别的用户绑定,不能再次绑定",
|
||||
}, nil
|
||||
}
|
||||
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var life = registerConfig.EmailVerification.Life
|
||||
if life <= 0 {
|
||||
life = userconfigs.EmailVerificationDefaultLife
|
||||
}
|
||||
|
||||
if int64(verification.CreatedAt) < time.Now().Unix()-int64(life) {
|
||||
return &pb.VerifyUserEmailResponse{
|
||||
UserId: 0,
|
||||
Email: verification.Email,
|
||||
ErrorCode: "EXPIRED_CODE",
|
||||
ErrorMessage: "激活码已过期",
|
||||
}, nil
|
||||
}
|
||||
|
||||
var userId = int64(verification.UserId)
|
||||
if verification.IsVerified {
|
||||
return &pb.VerifyUserEmailResponse{
|
||||
UserId: userId,
|
||||
Email: verification.Email,
|
||||
ErrorCode: "",
|
||||
ErrorMessage: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 设置已激活
|
||||
err = models.SharedUserDAO.UpdateUserVerifiedEmail(tx, userId, verification.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = models.SharedUserEmailVerificationDAO.UpdateVerificationIsVerified(tx, int64(verification.Id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.VerifyUserEmailResponse{
|
||||
UserId: userId,
|
||||
Email: verification.Email,
|
||||
ErrorCode: "",
|
||||
ErrorMessage: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendUserEmailVerification 发送邮箱认证
|
||||
func (this *UserEmailVerificationService) SendUserEmailVerification(ctx context.Context, req *pb.SendUserEmailVerificationRequest) (*pb.RPCSuccess, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId <= 0 {
|
||||
return nil, errors.New("invalid userId")
|
||||
}
|
||||
|
||||
_, err = mail.ParseAddress(req.Email)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid email '" + req.Email + "'")
|
||||
}
|
||||
|
||||
// 是否已启用认证
|
||||
var tx = this.NullTx()
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !registerConfig.EmailVerification.IsOn {
|
||||
return nil, errors.New("the email verification function is off")
|
||||
}
|
||||
|
||||
// 检查是否被使用
|
||||
emailUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedEmail(tx, req.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if emailUserId > 0 {
|
||||
if emailUserId != userId {
|
||||
return nil, errors.New("the email is using by other user")
|
||||
}
|
||||
|
||||
return nil, errors.New("the email is already verified")
|
||||
}
|
||||
|
||||
_, err = models.SharedUserEmailVerificationDAO.CreateVerification(tx, userId, req.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindLatestUserEmailVerification 查找用户正在等待激活的认证
|
||||
func (this *UserEmailVerificationService) FindLatestUserEmailVerification(ctx context.Context, req *pb.FindLatestUserEmailVerificationRequest) (*pb.FindLatestUserEmailVerificationResponse, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId <= 0 {
|
||||
return nil, errors.New("invalid userId")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
verification, err := models.SharedUserEmailVerificationDAO.FindUserLatestVerification(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if verification == nil || verification.IsVerified {
|
||||
return &pb.FindLatestUserEmailVerificationResponse{
|
||||
UserEmailVerification: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 过期时间
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var life = registerConfig.EmailVerification.Life
|
||||
if life <= 0 {
|
||||
life = userconfigs.EmailVerificationDefaultLife
|
||||
}
|
||||
|
||||
// 是否过期
|
||||
var expiresAt = int64(verification.CreatedAt) + int64(life)
|
||||
if expiresAt < time.Now().Unix() {
|
||||
return &pb.FindLatestUserEmailVerificationResponse{
|
||||
UserEmailVerification: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &pb.FindLatestUserEmailVerificationResponse{
|
||||
UserEmailVerification: &pb.UserEmailVerification{
|
||||
Id: int64(verification.Id),
|
||||
Email: verification.Email,
|
||||
UserId: int64(verification.UserId),
|
||||
Code: verification.Code,
|
||||
CreatedAt: int64(verification.CreatedAt),
|
||||
IsSent: verification.IsSent,
|
||||
IsVerified: verification.IsVerified,
|
||||
ExpiresAt: expiresAt,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
116
EdgeAPI/internal/rpc/services/users/service_user_ext.go
Normal file
116
EdgeAPI/internal/rpc/services/users/service_user_ext.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
// FindUserPriceInfo 读取用户计费信息
|
||||
func (this *UserService) FindUserPriceInfo(ctx context.Context, req *pb.FindUserPriceInfoRequest) (*pb.FindUserPriceInfoResponse, error) {
|
||||
return nil, this.NotImplementedYet()
|
||||
}
|
||||
|
||||
// UpdateUserPriceType 修改用户计费方式
|
||||
func (this *UserService) UpdateUserPriceType(ctx context.Context, req *pb.UpdateUserPriceTypeRequest) (*pb.RPCSuccess, error) {
|
||||
return nil, this.NotImplementedYet()
|
||||
}
|
||||
|
||||
// UpdateUserPricePeriod 修改用户计费周期
|
||||
func (this *UserService) UpdateUserPricePeriod(ctx context.Context, req *pb.UpdateUserPricePeriodRequest) (*pb.RPCSuccess, error) {
|
||||
return nil, this.NotImplementedYet()
|
||||
}
|
||||
|
||||
// RegisterUser 注册用户
|
||||
func (this *UserService) RegisterUser(ctx context.Context, req *pb.RegisterUserRequest) (*pb.RegisterUserResponse, error) {
|
||||
currentUserId, err := this.ValidateUserNode(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if currentUserId > 0 {
|
||||
return nil, this.PermissionError()
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查邮箱是否已被使用
|
||||
if len(req.Email) > 0 {
|
||||
emailUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedEmail(tx, req.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if emailUserId > 0 {
|
||||
return nil, errors.New("the email address '" + req.Email + "' is using by other user")
|
||||
}
|
||||
}
|
||||
|
||||
// 注册配置
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if registerConfig == nil || !registerConfig.IsOn {
|
||||
return nil, errors.New("the registration has been disabled")
|
||||
}
|
||||
|
||||
var requireEmailVerification = false
|
||||
var createdUserId int64
|
||||
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")
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
userId, err := models.SharedUserDAO.CreateUser(tx, req.Username, req.Password, req.Fullname, req.Mobile, "", req.Email, "", req.Source, registerConfig.ClusterId, registerConfig.Features, req.Ip, !registerConfig.RequireVerification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createdUserId = userId
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.RegisterUserResponse{
|
||||
UserId: createdUserId,
|
||||
RequireEmailVerification: requireEmailVerification,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FindUserFeatures 获取用户所有的功能列表
|
||||
func (this *UserService) FindUserFeatures(ctx context.Context, req *pb.FindUserFeaturesRequest) (*pb.FindUserFeaturesResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
features, err := models.SharedUserDAO.FindUserFeatures(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*pb.UserFeature{}
|
||||
for _, feature := range features {
|
||||
result = append(result, feature.ToPB())
|
||||
}
|
||||
|
||||
return &pb.FindUserFeaturesResponse{Features: result}, nil
|
||||
}
|
||||
196
EdgeAPI/internal/rpc/services/users/service_user_ext_plus.go
Normal file
196
EdgeAPI/internal/rpc/services/users/service_user_ext_plus.go
Normal file
@@ -0,0 +1,196 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
// FindUserPriceInfo 读取用户计费信息
|
||||
func (this *UserService) FindUserPriceInfo(ctx context.Context, req *pb.FindUserPriceInfoRequest) (*pb.FindUserPriceInfoResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
priceType, pricePeriod, err := models.SharedUserDAO.FindUserPriceInfo(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.FindUserPriceInfoResponse{
|
||||
PriceType: priceType,
|
||||
PricePeriod: pricePeriod,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateUserPriceType 修改用户计费方式
|
||||
func (this *UserService) UpdateUserPriceType(ctx context.Context, req *pb.UpdateUserPriceTypeRequest) (*pb.RPCSuccess, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
config, err := models.SharedSysSettingDAO.ReadUserPriceConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId > 0 && (config == nil || !config.IsOn || !config.UserCanChangePriceType) {
|
||||
return nil, this.PermissionError()
|
||||
}
|
||||
|
||||
if !userconfigs.IsValidPriceType(req.PriceType) {
|
||||
return nil, errors.New("invalid price type '" + req.PriceType + "'")
|
||||
}
|
||||
|
||||
err = models.SharedUserDAO.UpdateUserPriceType(tx, req.UserId, req.PriceType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// UpdateUserPricePeriod 修改用户计费周期
|
||||
func (this *UserService) UpdateUserPricePeriod(ctx context.Context, req *pb.UpdateUserPricePeriodRequest) (*pb.RPCSuccess, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
config, err := models.SharedSysSettingDAO.ReadUserPriceConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId > 0 && (config == nil || !config.IsOn || !config.UserCanChangePricePeriod) {
|
||||
return nil, this.PermissionError()
|
||||
}
|
||||
|
||||
if !userconfigs.IsValidPricePeriod(req.PricePeriod) {
|
||||
return nil, errors.New("invalid price period '" + req.PricePeriod + "'")
|
||||
}
|
||||
|
||||
err = models.SharedUserDAO.UpdateUserPricePeriod(tx, req.UserId, req.PricePeriod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// RegisterUser 注册用户
|
||||
func (this *UserService) RegisterUser(ctx context.Context, req *pb.RegisterUserRequest) (*pb.RegisterUserResponse, error) {
|
||||
currentUserId, err := this.ValidateUserNode(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if currentUserId > 0 {
|
||||
return nil, this.PermissionError()
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查邮箱是否已被使用
|
||||
if len(req.Email) > 0 {
|
||||
emailUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedEmail(tx, req.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if emailUserId > 0 {
|
||||
return nil, errors.New("the email address '" + req.Email + "' is using by other user")
|
||||
}
|
||||
}
|
||||
|
||||
// 注册配置
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if registerConfig == nil || !registerConfig.IsOn {
|
||||
return nil, errors.New("the registration has been disabled")
|
||||
}
|
||||
|
||||
var requireEmailVerification = false
|
||||
var createdUserId int64
|
||||
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")
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
userId, err := models.SharedUserDAO.CreateUser(tx, req.Username, req.Password, req.Fullname, req.Mobile, "", req.Email, "", req.Source, registerConfig.ClusterId, registerConfig.Features, req.Ip, !registerConfig.RequireVerification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createdUserId = userId
|
||||
|
||||
// 发送激活邮件
|
||||
if len(req.Email) > 0 && registerConfig.EmailVerification.IsOn {
|
||||
_, err := models.SharedUserEmailVerificationDAO.CreateVerification(tx, userId, req.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requireEmailVerification = true
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.RegisterUserResponse{
|
||||
UserId: createdUserId,
|
||||
RequireEmailVerification: requireEmailVerification,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FindUserFeatures 获取用户所有的功能列表
|
||||
func (this *UserService) FindUserFeatures(ctx context.Context, req *pb.FindUserFeaturesRequest) (*pb.FindUserFeaturesResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
features, err := models.SharedUserDAO.FindUserFeatures(tx, req.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*pb.UserFeature{}
|
||||
for _, feature := range features {
|
||||
result = append(result, feature.ToPB())
|
||||
}
|
||||
|
||||
return &pb.FindUserFeaturesResponse{Features: result}, nil
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/senders/smssenders"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserMobileVerificationService struct {
|
||||
services.BaseService
|
||||
}
|
||||
|
||||
// VerifyUserMobile 认证手机号码
|
||||
func (this *UserMobileVerificationService) VerifyUserMobile(ctx context.Context, req *pb.VerifyUserMobileRequest) (*pb.VerifyUserMobileResponse, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(req.Mobile) == 0 {
|
||||
return nil, errors.New("'mobile' should not be empty")
|
||||
}
|
||||
|
||||
if len(req.Code) == 0 {
|
||||
return nil, errors.New("'code' should not be empty")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
verification, err := models.SharedUserMobileVerificationDAO.FindVerificationWithCode(tx, userId, req.Mobile, req.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if verification == nil {
|
||||
return &pb.VerifyUserMobileResponse{
|
||||
UserId: 0,
|
||||
Mobile: "",
|
||||
ErrorCode: "WRONG_CODE",
|
||||
ErrorMessage: "你输入的验证码错误或已过期",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 手机号码是否已被别的用户所激活
|
||||
mobileUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedMobile(tx, verification.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mobileUserId > 0 && mobileUserId != int64(verification.UserId) {
|
||||
return &pb.VerifyUserMobileResponse{
|
||||
UserId: 0,
|
||||
Mobile: verification.Mobile,
|
||||
ErrorCode: "VERIFIED_MOBILE",
|
||||
ErrorMessage: "此手机号码已经被别的用户绑定,不能再次绑定",
|
||||
}, nil
|
||||
}
|
||||
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var life = registerConfig.MobileVerification.Life
|
||||
if life <= 0 {
|
||||
life = userconfigs.MobileVerificationDefaultLife
|
||||
}
|
||||
|
||||
if int64(verification.CreatedAt) < time.Now().Unix()-int64(life) {
|
||||
return &pb.VerifyUserMobileResponse{
|
||||
UserId: 0,
|
||||
Mobile: verification.Mobile,
|
||||
ErrorCode: "EXPIRED_CODE",
|
||||
ErrorMessage: "验证码已过期",
|
||||
}, nil
|
||||
}
|
||||
|
||||
var verificationUserId = int64(verification.UserId)
|
||||
if verification.IsVerified {
|
||||
return &pb.VerifyUserMobileResponse{
|
||||
UserId: verificationUserId,
|
||||
Mobile: verification.Mobile,
|
||||
ErrorCode: "",
|
||||
ErrorMessage: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 设置已激活
|
||||
err = models.SharedUserDAO.UpdateUserVerifiedMobile(tx, verificationUserId, verification.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = models.SharedUserMobileVerificationDAO.UpdateVerificationIsVerified(tx, int64(verification.Id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.VerifyUserMobileResponse{
|
||||
UserId: verificationUserId,
|
||||
Mobile: verification.Mobile,
|
||||
ErrorCode: "",
|
||||
ErrorMessage: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendUserMobileVerification 发送手机号码认证
|
||||
func (this *UserMobileVerificationService) SendUserMobileVerification(ctx context.Context, req *pb.SendUserMobileVerificationRequest) (*pb.SendUserMobileVerificationResponse, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId <= 0 {
|
||||
return nil, errors.New("invalid userId")
|
||||
}
|
||||
|
||||
if !utils.IsValidMobile(req.Mobile) {
|
||||
return nil, errors.New("invalid mobile '" + req.Mobile + "'")
|
||||
}
|
||||
|
||||
// TODO 增加单个IP的发送短信次数限制
|
||||
|
||||
// 是否超出次数
|
||||
var tx = this.NullTx()
|
||||
countDaily, err := models.SharedUserMobileVerificationDAO.CountUserDailyVerifications(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if countDaily >= userconfigs.MobileVerificationDailyLimit {
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "OVER_DAILY_LIMIT",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 是否已启用认证
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if registerConfig == nil || !registerConfig.MobileVerification.IsOn {
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "MOBILE_VERIFICATION_IS_OFF",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 系统是否已设置短信发送渠道
|
||||
senderConfig, err := models.SharedSysSettingDAO.ReadUserSenderConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if senderConfig == nil {
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "SENDER_NOT_CONFIGURED",
|
||||
}, nil
|
||||
}
|
||||
var smsSenderConfig = senderConfig.VerifySMS
|
||||
if smsSenderConfig == nil || !smsSenderConfig.IsOn {
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "SENDER_NOT_CONFIGURED",
|
||||
}, nil
|
||||
}
|
||||
senderParamsJSON, err := smsSenderConfig.ParamsJSON()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("format sender params error: %w", err)
|
||||
}
|
||||
sender, err := smssenders.CreateSender(smsSenderConfig.Type, senderParamsJSON)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create sender failed: %w", err)
|
||||
}
|
||||
if sender == nil {
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "CREATE_SENDER_FAILED",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 检查是否被使用
|
||||
mobileUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedMobile(tx, req.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mobileUserId > 0 {
|
||||
if mobileUserId != userId {
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "MOBILE_IS_USED",
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "MOBILE_IS_VERIFIED",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 创建新的
|
||||
var codeMin = 1
|
||||
for i := 0; i < userconfigs.MobileVerificationCodeLength-1; i++ {
|
||||
codeMin *= 10
|
||||
}
|
||||
var codeMax = 10*codeMin - 1
|
||||
var code = types.String(rands.Int(codeMin, codeMax))
|
||||
|
||||
// 发送短信验证码
|
||||
var body = registerConfig.MobileVerification.Body
|
||||
if len(body) == 0 {
|
||||
body = "Your Verify Code ${code}"
|
||||
}
|
||||
body = strings.Replace(body, "${code}", code, -1)
|
||||
_, isOk, err := sender.Send(req.Mobile, body, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isOk {
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "SEND_FAILED",
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = models.SharedUserMobileVerificationDAO.CreateVerification(tx, userId, req.Mobile, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.SendUserMobileVerificationResponse{
|
||||
IsOk: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FindLatestUserMobileVerification 查找用户正在等待激活的认证
|
||||
func (this *UserMobileVerificationService) FindLatestUserMobileVerification(ctx context.Context, req *pb.FindLatestUserMobileVerificationRequest) (*pb.FindLatestUserMobileVerificationResponse, error) {
|
||||
userId, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId <= 0 {
|
||||
return nil, errors.New("invalid userId")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
verification, err := models.SharedUserMobileVerificationDAO.FindUserLatestVerification(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if verification == nil || verification.IsVerified {
|
||||
return &pb.FindLatestUserMobileVerificationResponse{
|
||||
UserMobileVerification: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 过期时间
|
||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var life = registerConfig.MobileVerification.Life
|
||||
if life <= 0 {
|
||||
life = userconfigs.MobileVerificationDefaultLife
|
||||
}
|
||||
|
||||
// 是否过期
|
||||
var expiresAt = int64(verification.CreatedAt) + int64(life)
|
||||
if expiresAt < time.Now().Unix() {
|
||||
return &pb.FindLatestUserMobileVerificationResponse{
|
||||
UserMobileVerification: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &pb.FindLatestUserMobileVerificationResponse{
|
||||
UserMobileVerification: &pb.UserMobileVerification{
|
||||
Id: int64(verification.Id),
|
||||
Mobile: verification.Mobile,
|
||||
UserId: int64(verification.UserId),
|
||||
Code: verification.Code,
|
||||
CreatedAt: int64(verification.CreatedAt),
|
||||
IsSent: verification.IsSent,
|
||||
IsVerified: verification.IsVerified,
|
||||
ExpiresAt: expiresAt,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
// UserVerifyCodeService 用户验证码服务
|
||||
type UserVerifyCodeService struct {
|
||||
services.BaseService
|
||||
}
|
||||
|
||||
// SendUserVerifyCode 发送重置密码邮件验证码
|
||||
func (this *UserVerifyCodeService) SendUserVerifyCode(ctx context.Context, req *pb.SendUserVerifyCodeRequest) (*pb.SendUserVerifyCodeResponse, error) {
|
||||
_, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查用户
|
||||
userId, err := models.SharedUserDAO.FindUserId(tx, req.Email, req.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userId <= 0 {
|
||||
return nil, errors.New("can not find the user")
|
||||
}
|
||||
|
||||
code, err := models.SharedUserVerifyCodeDAO.CreateCode(tx, req.Type, req.Email, req.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.SendUserVerifyCodeResponse{
|
||||
CodeLength: types.Int32(len(code)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ValidateUserVerifyCode 校验验证码
|
||||
func (this *UserVerifyCodeService) ValidateUserVerifyCode(ctx context.Context, req *pb.ValidateUserVerifyCodeRequest) (*pb.ValidateUserVerifyCodeResponse, error) {
|
||||
_, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
verifyCode, err := models.SharedUserVerifyCodeDAO.FindCode(tx, req.Type, req.Email, req.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if verifyCode == nil {
|
||||
return &pb.ValidateUserVerifyCodeResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "NOT_FOUND",
|
||||
ErrorMessage: "找不到验证码或者已经失效",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if verifyCode.Code != req.Code {
|
||||
return &pb.ValidateUserVerifyCodeResponse{
|
||||
IsOk: false,
|
||||
ErrorCode: "WRONG_CODE",
|
||||
ErrorMessage: "验证码输入错误",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 执行业务代码
|
||||
switch req.Type {
|
||||
case models.UserVerifyCodeTypeResetPassword: // 找回密码
|
||||
// 查找用户
|
||||
userId, err := models.SharedUserDAO.FindUserId(tx, verifyCode.Email, verifyCode.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
if userId > 0 {
|
||||
err = models.SharedUserDAO.UpdateUserPassword(tx, userId, req.NewPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除
|
||||
err = models.SharedUserVerifyCodeDAO.DeleteCode(tx, int64(verifyCode.Id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.ValidateUserVerifyCodeResponse{
|
||||
IsOk: true,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user