Initial commit (code only without large binaries)
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package emailverify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"net/mail"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
// 是否可以激活Email
|
||||
registerConfig, _ := configloaders.LoadRegisterConfig()
|
||||
this.Data["canVerify"] = false
|
||||
if registerConfig == nil {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
var canVerify = registerConfig.EmailVerification.IsOn
|
||||
if !canVerify {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["canVerify"] = true
|
||||
|
||||
// 当前已激活邮箱
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{
|
||||
UserId: this.UserId(),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if userResp.User == nil {
|
||||
this.ErrorPage(errors.New("can not find user info"))
|
||||
return
|
||||
}
|
||||
this.Data["verifiedEmail"] = userResp.User.VerifiedEmail
|
||||
|
||||
// 现在正等待激活的邮箱
|
||||
latestVerificationResp, err := this.RPC().UserEmailVerificationRPC().FindLatestUserEmailVerification(this.UserContext(), &pb.FindLatestUserEmailVerificationRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var latestVerification = latestVerificationResp.UserEmailVerification
|
||||
if latestVerification == nil {
|
||||
this.Data["latestVerification"] = nil
|
||||
} else {
|
||||
this.Data["latestVerification"] = maps.Map{
|
||||
"email": latestVerification.Email,
|
||||
"expiresTime": timeutil.FormatTime("Y-m-d H:i:s", latestVerification.ExpiresAt),
|
||||
"isSent": latestVerification.IsSent,
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
Email string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
if len(params.Email) == 0 {
|
||||
this.FailField("email", "请输入要激活的邮箱")
|
||||
return
|
||||
}
|
||||
|
||||
_, err := mail.ParseAddress(params.Email)
|
||||
if err != nil {
|
||||
this.FailField("email", "邮箱格式不正确")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查邮件是否已被使用
|
||||
checkResp, err := this.RPC().UserRPC().CheckUserEmail(this.UserContext(), &pb.CheckUserEmailRequest{Email: params.Email})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if checkResp.Exists {
|
||||
this.FailField("email", "当前邮箱已被别的用户使用,请换一个")
|
||||
return
|
||||
}
|
||||
|
||||
// 如果同自己已认证邮箱一致,则不重复发送
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{UserId: this.UserId()})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if userResp.User == nil {
|
||||
this.Fail("can not find current user")
|
||||
return
|
||||
}
|
||||
if userResp.User.VerifiedEmail == params.Email {
|
||||
this.FailField("email", "此邮箱已激活,无需再次激活")
|
||||
return
|
||||
}
|
||||
|
||||
// 发送激活邮件
|
||||
_, err = this.RPC().UserEmailVerificationRPC().SendUserEmailVerification(this.UserContext(), &pb.SendUserEmailVerificationRequest{Email: params.Email})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package emailverify
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Helper(settingutils.NewHelper("profile")).
|
||||
Prefix("/settings/email-verify").
|
||||
GetPost("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type CancelAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CancelAction) RunPost(params struct {
|
||||
IdentityId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserIdentity_LogCancelUserIdentity)
|
||||
|
||||
_, err := this.RPC().UserIdentityRPC().CancelUserIdentity(this.UserContext(), &pb.CancelUserIdentityRequest{UserIdentityId: params.IdentityId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type EnterpriseAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *EnterpriseAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *EnterpriseAction) RunGet(params struct{}) {
|
||||
resp, err := this.RPC().UserIdentityRPC().FindEnabledUserIdentityWithOrgType(this.UserContext(), &pb.FindEnabledUserIdentityWithOrgTypeRequest{
|
||||
OrgType: userconfigs.UserIdentityOrgTypeEnterprise,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var userIdentity = resp.UserIdentity
|
||||
if userIdentity == nil {
|
||||
this.Data["identity"] = nil
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
if len(userIdentity.FileIds) != 1 {
|
||||
this.Data["identity"] = nil
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["identity"] = maps.Map{
|
||||
"id": userIdentity.Id,
|
||||
"realName": userIdentity.RealName,
|
||||
"number": userIdentity.Number,
|
||||
"status": userIdentity.Status,
|
||||
"frontFileId": userIdentity.FileIds[0],
|
||||
"rejectReason": userIdentity.RejectReason,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
// 个人认证
|
||||
{
|
||||
resp, err := this.RPC().UserIdentityRPC().FindEnabledUserIdentityWithOrgType(this.UserContext(), &pb.FindEnabledUserIdentityWithOrgTypeRequest{
|
||||
UserId: this.UserId(),
|
||||
OrgType: userconfigs.UserIdentityOrgTypeIndividual,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.UserIdentity == nil {
|
||||
this.Data["individualIdentity"] = nil
|
||||
} else {
|
||||
this.Data["individualIdentity"] = maps.Map{
|
||||
"realName": resp.UserIdentity.RealName,
|
||||
"status": resp.UserIdentity.Status,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 企业认证
|
||||
{
|
||||
resp, err := this.RPC().UserIdentityRPC().FindEnabledUserIdentityWithOrgType(this.UserContext(), &pb.FindEnabledUserIdentityWithOrgTypeRequest{
|
||||
UserId: this.UserId(),
|
||||
OrgType: userconfigs.UserIdentityOrgTypeEnterprise,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.UserIdentity == nil {
|
||||
this.Data["enterpriseIdentity"] = nil
|
||||
} else {
|
||||
this.Data["enterpriseIdentity"] = maps.Map{
|
||||
"realName": resp.UserIdentity.RealName,
|
||||
"status": resp.UserIdentity.Status,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndividualAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndividualAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndividualAction) RunGet(params struct{}) {
|
||||
resp, err := this.RPC().UserIdentityRPC().FindEnabledUserIdentityWithOrgType(this.UserContext(), &pb.FindEnabledUserIdentityWithOrgTypeRequest{
|
||||
OrgType: userconfigs.UserIdentityOrgTypeIndividual,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var userIdentity = resp.UserIdentity
|
||||
if userIdentity == nil {
|
||||
this.Data["identity"] = nil
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
if len(userIdentity.FileIds) != 2 {
|
||||
this.Data["identity"] = nil
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["identity"] = maps.Map{
|
||||
"id": userIdentity.Id,
|
||||
"realName": userIdentity.RealName,
|
||||
"number": userIdentity.Number,
|
||||
"status": userIdentity.Status,
|
||||
"frontFileId": userIdentity.FileIds[1],
|
||||
"backFileId": userIdentity.FileIds[0],
|
||||
"rejectReason": userIdentity.RejectReason,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Helper(settingutils.NewHelper("identity")).
|
||||
Prefix("/settings/identity").
|
||||
Get("", new(IndexAction)).
|
||||
Get("/individual", new(IndividualAction)).
|
||||
Get("/enterprise", new(EnterpriseAction)).
|
||||
Post("/uploadIndividual", new(UploadIndividualAction)).
|
||||
Post("/uploadEnterprise", new(UploadEnterpriseAction)).
|
||||
Post("/submit", new(SubmitAction)).
|
||||
Post("/cancel", new(CancelAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type SubmitAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SubmitAction) RunPost(params struct {
|
||||
IdentityId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserIdentity_LogSubmitUserIdentity)
|
||||
|
||||
_, err := this.RPC().UserIdentityRPC().SubmitUserIdentity(this.UserContext(), &pb.SubmitUserIdentityRequest{UserIdentityId: params.IdentityId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils/sizes"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UploadEnterpriseAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UploadEnterpriseAction) RunPost(params struct {
|
||||
IdentityId int64
|
||||
|
||||
RealName string
|
||||
Number string
|
||||
FrontFile *actions.File
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserIdentity_LogUpdateUserIdentityEnterprise)
|
||||
|
||||
// 检查IdentityId
|
||||
var identityId = params.IdentityId
|
||||
var oldFileIds = []int64{0, 0}
|
||||
if identityId > 0 {
|
||||
identityResp, err := this.RPC().UserIdentityRPC().FindEnabledUserIdentity(this.UserContext(), &pb.FindEnabledUserIdentityRequest{
|
||||
UserIdentityId: identityId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if identityResp.UserIdentity == nil {
|
||||
this.Fail("错误的表单数据,请刷新后重试")
|
||||
}
|
||||
|
||||
var status = identityResp.UserIdentity.Status
|
||||
if status != userconfigs.UserIdentityStatusNone && status != userconfigs.UserIdentityStatusRejected {
|
||||
this.Fail("当前状态下无法修改")
|
||||
}
|
||||
|
||||
oldFileIds = identityResp.UserIdentity.FileIds
|
||||
}
|
||||
var mustUpload = identityId <= 0
|
||||
|
||||
params.Must.
|
||||
Field("realName", params.RealName).
|
||||
Require("请输入企业全称").
|
||||
Field("number", params.Number).
|
||||
Require("请输入营业执照号码")
|
||||
|
||||
var number = regexp.MustCompile(`\s+`).ReplaceAllString(params.Number, "")
|
||||
number = strings.ToUpper(number)
|
||||
|
||||
// front
|
||||
var frontFile = params.FrontFile
|
||||
if frontFile == nil {
|
||||
if mustUpload {
|
||||
this.Fail("请上传营业执照照片")
|
||||
}
|
||||
} else {
|
||||
var frontContentType = strings.ToLower(frontFile.ContentType)
|
||||
_, ok := allowedContentTypes[frontContentType]
|
||||
if !ok {
|
||||
this.Fail("请上传正确格式的图片")
|
||||
}
|
||||
|
||||
// TODO 需要可以配置最大上传尺寸,包括界面上的提示
|
||||
if frontFile.Size > 8*sizes.M {
|
||||
this.Fail("要上传的图片(营业执照照片)不能超过8MiB")
|
||||
}
|
||||
}
|
||||
|
||||
// 上传到服务器
|
||||
|
||||
var frontFileId int64 = 0
|
||||
|
||||
if frontFile != nil {
|
||||
fileId, ok, err := this.UploadFile(frontFile, "enterprise.license")
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
this.Fail("上传失败,请刷新后重试")
|
||||
}
|
||||
frontFileId = fileId
|
||||
}
|
||||
|
||||
if len(oldFileIds) == 1 {
|
||||
if frontFileId == 0 {
|
||||
frontFileId = oldFileIds[0]
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if identityId > 0 {
|
||||
_, err = this.RPC().UserIdentityRPC().UpdateUserIdentity(this.UserContext(), &pb.UpdateUserIdentityRequest{
|
||||
UserIdentityId: identityId,
|
||||
Type: userconfigs.UserIdentityTypeEnterpriseLicense,
|
||||
RealName: params.RealName,
|
||||
Number: number,
|
||||
FileIds: []int64{frontFileId},
|
||||
})
|
||||
} else {
|
||||
_, err = this.RPC().UserIdentityRPC().CreateUserIdentity(this.UserContext(), &pb.CreateUserIdentityRequest{
|
||||
OrgType: userconfigs.UserIdentityOrgTypeEnterprise,
|
||||
Type: userconfigs.UserIdentityTypeEnterpriseLicense,
|
||||
RealName: params.RealName,
|
||||
Number: number,
|
||||
FileIds: []int64{frontFileId},
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package identity
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils/sizes"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var allowedContentTypes = map[string]bool{
|
||||
"image/png": true,
|
||||
"image/jpeg": true,
|
||||
}
|
||||
|
||||
type UploadIndividualAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UploadIndividualAction) RunPost(params struct {
|
||||
IdentityId int64
|
||||
|
||||
RealName string
|
||||
Number string
|
||||
BackFile *actions.File
|
||||
FrontFile *actions.File
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserIdentity_LogUpdateUserIdentityIndividual)
|
||||
|
||||
// 检查IdentityId
|
||||
var identityId = params.IdentityId
|
||||
var oldFileIds = []int64{0, 0}
|
||||
if identityId > 0 {
|
||||
identityResp, err := this.RPC().UserIdentityRPC().FindEnabledUserIdentity(this.UserContext(), &pb.FindEnabledUserIdentityRequest{
|
||||
UserIdentityId: identityId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if identityResp.UserIdentity == nil {
|
||||
this.Fail("错误的表单数据,请刷新后重试")
|
||||
}
|
||||
|
||||
var status = identityResp.UserIdentity.Status
|
||||
if status != userconfigs.UserIdentityStatusNone && status != userconfigs.UserIdentityStatusRejected {
|
||||
this.Fail("当前状态下无法修改")
|
||||
}
|
||||
|
||||
oldFileIds = identityResp.UserIdentity.FileIds
|
||||
}
|
||||
var mustUpload = identityId <= 0
|
||||
|
||||
params.Must.
|
||||
Field("realName", params.RealName).
|
||||
Require("请输入真实姓名").
|
||||
Field("number", params.Number).
|
||||
Require("请输入身份证号")
|
||||
|
||||
var number = regexp.MustCompile(`\s+`).ReplaceAllString(params.Number, "")
|
||||
number = strings.ToUpper(number)
|
||||
if !regexp.MustCompile(`^\d+(X)?$`).MatchString(number) {
|
||||
this.FailField("number", "身份证号中只能含有数字和X字母")
|
||||
}
|
||||
var numberLen = len(number)
|
||||
if numberLen != 15 && numberLen != 18 {
|
||||
this.FailField("number", "身份证号只能是15或者18位")
|
||||
}
|
||||
|
||||
// back
|
||||
var backFile = params.BackFile
|
||||
if backFile == nil {
|
||||
if mustUpload {
|
||||
this.Fail("请上传身份证-照片面")
|
||||
}
|
||||
} else {
|
||||
var backContentType = strings.ToLower(backFile.ContentType)
|
||||
_, ok := allowedContentTypes[backContentType]
|
||||
if !ok {
|
||||
this.Fail("请上传正确格式的图片")
|
||||
}
|
||||
|
||||
// TODO 需要可以配置最大上传尺寸,包括界面上的提示
|
||||
if backFile.Size > 8*sizes.M {
|
||||
this.Fail("要上传的图片(身份证-照片面)不能超过8MiB")
|
||||
}
|
||||
}
|
||||
|
||||
// front
|
||||
var frontFile = params.FrontFile
|
||||
if frontFile == nil {
|
||||
if mustUpload {
|
||||
this.Fail("请上传身份证-国徽面")
|
||||
}
|
||||
} else {
|
||||
var frontContentType = strings.ToLower(frontFile.ContentType)
|
||||
_, ok := allowedContentTypes[frontContentType]
|
||||
if !ok {
|
||||
this.Fail("请上传正确格式的图片")
|
||||
}
|
||||
|
||||
// TODO 需要可以配置最大上传尺寸,包括界面上的提示
|
||||
if frontFile.Size > 8*sizes.M {
|
||||
this.Fail("要上传的图片(身份证-国徽面)不能超过8MiB")
|
||||
}
|
||||
}
|
||||
|
||||
// 上传到服务器
|
||||
var backFileId int64 = 0
|
||||
var frontFileId int64 = 0
|
||||
|
||||
if backFile != nil {
|
||||
fileId, ok, err := this.UploadFile(backFile, "user.idcard")
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
this.Fail("上传失败,请刷新后重试")
|
||||
}
|
||||
backFileId = fileId
|
||||
}
|
||||
|
||||
if frontFile != nil {
|
||||
fileId, ok, err := this.UploadFile(frontFile, "user.idcard")
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
this.Fail("上传失败,请刷新后重试")
|
||||
}
|
||||
frontFileId = fileId
|
||||
}
|
||||
|
||||
if len(oldFileIds) == 2 {
|
||||
if backFileId == 0 {
|
||||
backFileId = oldFileIds[0]
|
||||
}
|
||||
if frontFileId == 0 {
|
||||
frontFileId = oldFileIds[1]
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if identityId > 0 {
|
||||
_, err = this.RPC().UserIdentityRPC().UpdateUserIdentity(this.UserContext(), &pb.UpdateUserIdentityRequest{
|
||||
UserIdentityId: identityId,
|
||||
Type: userconfigs.UserIdentityTypeIDCard,
|
||||
RealName: params.RealName,
|
||||
Number: number,
|
||||
FileIds: []int64{backFileId, frontFileId},
|
||||
})
|
||||
} else {
|
||||
_, err = this.RPC().UserIdentityRPC().CreateUserIdentity(this.UserContext(), &pb.CreateUserIdentityRequest{
|
||||
OrgType: userconfigs.UserIdentityOrgTypeIndividual,
|
||||
Type: userconfigs.UserIdentityTypeIDCard,
|
||||
RealName: params.RealName,
|
||||
Number: number,
|
||||
FileIds: []int64{backFileId, frontFileId},
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
104
EdgeUser/internal/web/actions/default/settings/login/index.go
Normal file
104
EdgeUser/internal/web/actions/default/settings/login/index.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{UserId: this.UserId()})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var user = userResp.User
|
||||
if user == nil {
|
||||
this.NotFound("user", this.UserId())
|
||||
return
|
||||
}
|
||||
this.Data["user"] = maps.Map{
|
||||
"username": user.Username,
|
||||
"fullname": user.Fullname,
|
||||
}
|
||||
|
||||
config, _ := configloaders.LoadRegisterConfig()
|
||||
if config != nil {
|
||||
this.Data["complexPassword"] = config.ComplexPassword
|
||||
} else {
|
||||
this.Data["complexPassword"] = false
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
Username string
|
||||
Password string
|
||||
Password2 string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserLogin_LogUpdateLogin)
|
||||
|
||||
var must = params.Must
|
||||
must.Field("username", params.Username).
|
||||
Require("请输入用户名").
|
||||
Match("^[a-zA-Z0-9_]+$", "用户名中只能包含英文字母、数字、下划线").
|
||||
MinLength(6, "用户名长度不能少于6位")
|
||||
|
||||
existsResp, err := this.RPC().UserRPC().CheckUserUsername(this.UserContext(), &pb.CheckUserUsernameRequest{
|
||||
UserId: this.UserId(),
|
||||
Username: params.Username,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if existsResp.Exists {
|
||||
this.FailField("username", "此用户名已经被别的用户使用,请换一个")
|
||||
}
|
||||
|
||||
// 密码
|
||||
if len(params.Password) > 0 {
|
||||
must.
|
||||
Field("password", params.Password).
|
||||
Require("请输入密码").
|
||||
MinLength(6, "密码长度不能小于6位")
|
||||
|
||||
config, err := configloaders.LoadRegisterConfig()
|
||||
if err == nil {
|
||||
if config.ComplexPassword && (!regexp.MustCompile(`[a-z]`).MatchString(params.Password) || !regexp.MustCompile(`[A-Z]`).MatchString(params.Password)) {
|
||||
this.FailField("password", "为了您的账号安全,密码中必须包含大写和小写字母")
|
||||
}
|
||||
}
|
||||
|
||||
if params.Password != params.Password2 {
|
||||
this.FailField("password2", "两次输入的密码不一致")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().UserRPC().UpdateUserLogin(this.UserContext(), &pb.UpdateUserLoginRequest{
|
||||
UserId: this.UserId(),
|
||||
Username: params.Username,
|
||||
Password: params.Password,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
18
EdgeUser/internal/web/actions/default/settings/login/init.go
Normal file
18
EdgeUser/internal/web/actions/default/settings/login/init.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Helper(settingutils.NewHelper("login")).
|
||||
Prefix("/settings/login").
|
||||
GetPost("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package mfa
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type DisableAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DisableAction) RunPost(params struct{}) {
|
||||
_, err := this.RPC().LoginRPC().UpdateLogin(this.UserContext(), &pb.UpdateLoginRequest{
|
||||
Login: &pb.Login{
|
||||
Type: "otp",
|
||||
IsOn: false,
|
||||
UserId: this.UserId(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
50
EdgeUser/internal/web/actions/default/settings/mfa/enable.go
Normal file
50
EdgeUser/internal/web/actions/default/settings/mfa/enable.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package mfa
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/xlzd/gotp"
|
||||
)
|
||||
|
||||
type EnableAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *EnableAction) RunPost(params struct{}) {
|
||||
// 修改OTP
|
||||
otpLoginResp, err := this.RPC().LoginRPC().FindEnabledLogin(this.UserContext(), &pb.FindEnabledLoginRequest{
|
||||
Type: "otp",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
{
|
||||
var otpLogin = otpLoginResp.Login
|
||||
if otpLogin == nil {
|
||||
otpLogin = &pb.Login{
|
||||
Id: 0,
|
||||
Type: "otp",
|
||||
ParamsJSON: maps.Map{
|
||||
"secret": gotp.RandomSecret(16), // TODO 改成可以设置secret长度
|
||||
}.AsJSON(),
|
||||
IsOn: true,
|
||||
UserId: this.UserId(),
|
||||
}
|
||||
} else {
|
||||
// 如果已经有了,就覆盖,这样可以保留既有的参数
|
||||
otpLogin.IsOn = true
|
||||
}
|
||||
|
||||
_, err = this.RPC().LoginRPC().UpdateLogin(this.UserContext(), &pb.UpdateLoginRequest{Login: otpLogin})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
48
EdgeUser/internal/web/actions/default/settings/mfa/index.go
Normal file
48
EdgeUser/internal/web/actions/default/settings/mfa/index.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package mfa
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var user = userResp.User
|
||||
if user == nil {
|
||||
this.NotFound("User", this.UserId())
|
||||
return
|
||||
}
|
||||
|
||||
// OTP
|
||||
this.Data["otp"] = nil
|
||||
if user.OtpLogin != nil && user.OtpLogin.IsOn {
|
||||
loginParams := maps.Map{}
|
||||
err = json.Unmarshal(user.OtpLogin.ParamsJSON, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["otp"] = maps.Map{
|
||||
"isOn": true,
|
||||
"params": loginParams,
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
21
EdgeUser/internal/web/actions/default/settings/mfa/init.go
Normal file
21
EdgeUser/internal/web/actions/default/settings/mfa/init.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package mfa
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Helper(settingutils.NewHelper("mfa")).
|
||||
Prefix("/settings/mfa").
|
||||
GetPost("", new(IndexAction)).
|
||||
Get("/otpQrcode", new(OtpQrcodeAction)).
|
||||
Post("/enable", new(EnableAction)).
|
||||
Post("/disable", new(DisableAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package mfa
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils/otputils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"github.com/xlzd/gotp"
|
||||
)
|
||||
|
||||
type OtpQrcodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OtpQrcodeAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *OtpQrcodeAction) RunGet(params struct {
|
||||
Download bool
|
||||
}) {
|
||||
var userId = this.UserId()
|
||||
|
||||
loginResp, err := this.RPC().LoginRPC().FindEnabledLogin(this.UserContext(), &pb.FindEnabledLoginRequest{
|
||||
Type: "otp",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var login = loginResp.Login
|
||||
if login == nil || !login.IsOn {
|
||||
this.NotFound("userLogin", userId)
|
||||
return
|
||||
}
|
||||
|
||||
var loginParams = maps.Map{}
|
||||
err = json.Unmarshal(login.ParamsJSON, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var secret = loginParams.GetString("secret")
|
||||
|
||||
// 当前用户信息
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var user = userResp.User
|
||||
if user == nil {
|
||||
this.NotFound("user", userId)
|
||||
return
|
||||
}
|
||||
|
||||
uiConfig, err := configloaders.LoadUIConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var productName = uiConfig.ProductName
|
||||
if len(productName) == 0 {
|
||||
productName = "GoEdge用户"
|
||||
}
|
||||
var url = gotp.NewDefaultTOTP(secret).ProvisioningUri(user.Username, productName)
|
||||
data, err := qrcode.Encode(otputils.FixIssuer(url), qrcode.Medium, 256)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if params.Download {
|
||||
var filename = "OTP-USER-" + user.Username + ".png"
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+filename+"\";")
|
||||
}
|
||||
this.AddHeader("Content-Type", "image/png")
|
||||
this.AddHeader("Content-Length", types.String(len(data)))
|
||||
_, _ = this.Write(data)
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package mobileverify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ViewOnly bool
|
||||
}) {
|
||||
this.Data["isModifying"] = !params.ViewOnly
|
||||
this.Data["verifiedMobile"] = ""
|
||||
|
||||
// 是否可以激活手机号码
|
||||
registerConfig, _ := configloaders.LoadRegisterConfig()
|
||||
this.Data["canVerify"] = false
|
||||
if registerConfig == nil {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
var canVerify = registerConfig.MobileVerification.IsOn
|
||||
if !canVerify {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["canVerify"] = true
|
||||
this.Data["forceVerify"] = registerConfig.MobileVerification.Force
|
||||
|
||||
// 当前已激活手机号码
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{
|
||||
UserId: this.UserId(),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if userResp.User == nil {
|
||||
this.ErrorPage(errors.New("can not find user info"))
|
||||
return
|
||||
}
|
||||
this.Data["verifiedMobile"] = userResp.User.VerifiedMobile
|
||||
|
||||
// 有效期
|
||||
var smsLife = userconfigs.MobileVerificationDefaultLife
|
||||
if smsLife%60 == 0 {
|
||||
this.Data["smsLife"] = types.String(smsLife/60) + "分钟"
|
||||
} else {
|
||||
this.Data["smsLife"] = types.String(smsLife) + "秒钟"
|
||||
}
|
||||
this.Data["smsCodeLength"] = userconfigs.MobileVerificationCodeLength
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
Mobile string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
if len(params.Mobile) == 0 {
|
||||
this.FailField("mobile", "请输入要激活的手机号码")
|
||||
return
|
||||
}
|
||||
|
||||
if !utils.IsValidMobile(params.Mobile) {
|
||||
this.FailField("mobile", "手机号码格式不正确")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查手机号码是否已被使用
|
||||
checkResp, err := this.RPC().UserRPC().CheckUserMobile(this.UserContext(), &pb.CheckUserMobileRequest{Mobile: params.Mobile})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if checkResp.Exists {
|
||||
this.FailField("mobile", "当前手机号码已被别的用户使用,请换一个")
|
||||
return
|
||||
}
|
||||
|
||||
// 如果同自己已认证手机号码一致,则不重复发送
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{UserId: this.UserId()})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if userResp.User == nil {
|
||||
this.Fail("can not find current user")
|
||||
return
|
||||
}
|
||||
if userResp.User.VerifiedMobile == params.Mobile {
|
||||
this.FailField("mobile", "此手机号码已激活,无需再次激活")
|
||||
return
|
||||
}
|
||||
|
||||
// 发送激活短信
|
||||
resp, err := this.RPC().UserMobileVerificationRPC().SendUserMobileVerification(this.UserContext(), &pb.SendUserMobileVerificationRequest{Mobile: params.Mobile})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !resp.IsOk {
|
||||
if len(resp.ErrorCode) > 0 {
|
||||
this.Fail("短信发送失败,请稍后重试(错误代号:" + resp.ErrorCode + ")")
|
||||
} else {
|
||||
this.Fail("短信发送失败,请稍后重试")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package mobileverify
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Helper(settingutils.NewHelper("profile")).
|
||||
Prefix("/settings/mobile-verify").
|
||||
GetPost("", new(IndexAction)).
|
||||
Post("/verify", new(VerifyAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package mobileverify
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type VerifyAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *VerifyAction) RunPost(params struct {
|
||||
Mobile string
|
||||
Code string
|
||||
}) {
|
||||
if len(params.Code) != userconfigs.MobileVerificationCodeLength ||
|
||||
!regexp.MustCompile(`^\d+$`).MatchString(params.Code) {
|
||||
this.FailField("code", "请输入正确的验证码")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := this.RPC().UserMobileVerificationRPC().VerifyUserMobile(this.UserContext(), &pb.VerifyUserMobileRequest{
|
||||
Mobile: params.Mobile,
|
||||
Code: params.Code,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(resp.ErrorCode) > 0 {
|
||||
this.FailField("code", resp.ErrorMessage)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
116
EdgeUser/internal/web/actions/default/settings/profile/index.go
Normal file
116
EdgeUser/internal/web/actions/default/settings/profile/index.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.UserContext(), &pb.FindEnabledUserRequest{UserId: this.UserId()})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var user = userResp.User
|
||||
if user == nil {
|
||||
this.NotFound("user", this.UserId())
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["user"] = maps.Map{
|
||||
"fullname": user.Fullname,
|
||||
"email": user.Email,
|
||||
"verifiedEmail": user.VerifiedEmail,
|
||||
"mobile": user.Mobile,
|
||||
"verifiedMobile": user.VerifiedMobile,
|
||||
"isVerified": user.IsVerified,
|
||||
"isRejected": user.IsRejected,
|
||||
"rejectReason": user.RejectReason,
|
||||
}
|
||||
|
||||
// 邮箱是否需要激活
|
||||
registerConfig, err := configloaders.LoadRegisterConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["emailRequireVerification"] = registerConfig != nil && registerConfig.EmailVerification.IsOn
|
||||
|
||||
// 现在正等待激活的邮箱
|
||||
latestEmailVerificationResp, err := this.RPC().UserEmailVerificationRPC().FindLatestUserEmailVerification(this.UserContext(), &pb.FindLatestUserEmailVerificationRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var latestEmailVerification = latestEmailVerificationResp.UserEmailVerification
|
||||
if latestEmailVerification == nil {
|
||||
this.Data["latestEmailVerification"] = nil
|
||||
} else {
|
||||
this.Data["latestEmailVerification"] = maps.Map{
|
||||
"email": latestEmailVerification.Email,
|
||||
"expiresTime": timeutil.FormatTime("Y-m-d H:i:s", latestEmailVerification.ExpiresAt),
|
||||
"isSent": latestEmailVerification.IsSent,
|
||||
}
|
||||
}
|
||||
|
||||
// 手机号码是否需要激活
|
||||
this.Data["mobileRequireVerification"] = registerConfig != nil && registerConfig.MobileVerification.IsOn
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
Fullname string
|
||||
Mobile string
|
||||
Email string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.User_LogUpdateUserProfile)
|
||||
|
||||
var must = params.Must
|
||||
|
||||
// 手机号
|
||||
must.Field("mobile", params.Mobile).
|
||||
Require("请输入手机号").
|
||||
Mobile("请输入正确的手机号")
|
||||
|
||||
// 邮箱
|
||||
must.Field("email", params.Email).
|
||||
Require("请输入邮箱").
|
||||
Email("请输入正确的邮箱")
|
||||
|
||||
// 全名
|
||||
must.Field("fullname", params.Fullname).
|
||||
Require("请输入姓名或者公司名称")
|
||||
|
||||
params.Must.
|
||||
Field("fullname", params.Fullname).
|
||||
Require("请输入你的姓名")
|
||||
|
||||
_, err := this.RPC().UserRPC().UpdateUserInfo(this.UserContext(), &pb.UpdateUserInfoRequest{
|
||||
UserId: this.UserId(),
|
||||
Fullname: params.Fullname,
|
||||
Mobile: params.Mobile,
|
||||
Email: params.Email,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Helper(settingutils.NewHelper("profile")).
|
||||
Prefix("/settings/profile").
|
||||
GetPost("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package settingutils
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
tab string
|
||||
}
|
||||
|
||||
func NewHelper(tab string) *Helper {
|
||||
return &Helper{
|
||||
tab: tab,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||
goNext = true
|
||||
|
||||
var action = actionPtr.Object()
|
||||
|
||||
// 左侧菜单
|
||||
action.Data["teaMenu"] = "settings"
|
||||
|
||||
// 标签栏
|
||||
tabbar := actionutils.NewTabbar()
|
||||
tabbar.Add("个人资料", "", "/settings/profile", "", this.tab == "profile")
|
||||
tabbar.Add("实名认证", "", "/settings/identity", "", this.tab == "identity")
|
||||
tabbar.Add("多因子认证", "", "/settings/mfa", "", this.tab == "mfa")
|
||||
tabbar.Add("登录设置", "", "/settings/login", "", this.tab == "login")
|
||||
actionutils.SetTabbar(actionPtr, tabbar)
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user