Feat: user register / send activate email
This commit is contained in:
parent
7c07b623f6
commit
81d6988a50
8 changed files with 126 additions and 9 deletions
|
@ -83,8 +83,8 @@ func addDefaultSettings() {
|
|||
{Name: "siteURL", Value: ``, Type: "basic"},
|
||||
{Name: "siteName", Value: `Cloudreve`, Type: "basic"},
|
||||
{Name: "siteStatus", Value: `open`, Type: "basic"},
|
||||
{Name: "regStatus", Value: `0`, Type: "register"},
|
||||
{Name: "defaultGroup", Value: `3`, Type: "register"},
|
||||
{Name: "register_enabled", Value: `1`, Type: "register"},
|
||||
{Name: "default_group", Value: `2`, Type: "register"},
|
||||
{Name: "siteKeywords", Value: `网盘,网盘`, Type: "basic"},
|
||||
{Name: "siteDes", Value: `Cloudreve`, Type: "basic"},
|
||||
{Name: "siteTitle", Value: `平步云端`, Type: "basic"},
|
||||
|
@ -177,7 +177,7 @@ Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; verti
|
|||
}
|
||||
|
||||
for _, value := range defaultSettings {
|
||||
DB.Where(Setting{Name: value.Name}).FirstOrCreate(&value)
|
||||
DB.Where(Setting{Name: value.Name}).Create(&value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,11 +31,9 @@ type User struct {
|
|||
Password string `json:"-"`
|
||||
Status int
|
||||
GroupID uint
|
||||
ActivationKey string `json:"-"`
|
||||
Storage uint64
|
||||
OpenID string `json:"-"`
|
||||
TwoFactor string `json:"-"`
|
||||
Delay int
|
||||
Avatar string
|
||||
Options string `json:"-",gorm:"type:text"`
|
||||
Authn string `gorm:"type:text"`
|
||||
|
@ -55,8 +53,8 @@ type User struct {
|
|||
// UserOption 用户个性化配置字段
|
||||
type UserOption struct {
|
||||
ProfileOff bool `json:"profile_off,omitempty"`
|
||||
PreferredPolicy uint `json:"preferred_policy"`
|
||||
PreferredTheme string `json:"preferred_theme"`
|
||||
PreferredPolicy uint `json:"preferred_policy,omitempty"`
|
||||
PreferredTheme string `json:"preferred_theme,omitempty"`
|
||||
}
|
||||
|
||||
// Root 获取用户的根目录
|
||||
|
@ -190,7 +188,6 @@ func GetUserByEmail(email string) (User, error) {
|
|||
func NewUser() User {
|
||||
options := UserOption{}
|
||||
return User{
|
||||
Avatar: "default",
|
||||
OptionsSerialized: options,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,3 +19,17 @@ func NewOveruseNotification(userName, reason string) (string, string) {
|
|||
return fmt.Sprintf("【%s】空间容量超额提醒", options["siteName"]),
|
||||
util.Replace(replace, options["over_used_template"])
|
||||
}
|
||||
|
||||
// NewActivationEmail 新建激活邮件
|
||||
func NewActivationEmail(userName, activateURL string) (string, string) {
|
||||
options := model.GetSettingByNames("siteName", "siteURL", "siteTitle", "mail_activation_template")
|
||||
replace := map[string]string{
|
||||
"{siteTitle}": options["siteName"],
|
||||
"{userName}": userName,
|
||||
"{activationUrl}": activateURL,
|
||||
"{siteUrl}": options["siteURL"],
|
||||
"{siteSecTitle}": options["siteTitle"],
|
||||
}
|
||||
return fmt.Sprintf("【%s】注册激活", options["siteName"]),
|
||||
util.Replace(replace, options["mail_activation_template"])
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ func SetSession(c *gin.Context, list map[string]interface{}) {
|
|||
// GetSession 获取session
|
||||
func GetSession(c *gin.Context, key string) interface{} {
|
||||
s := sessions.Default(c)
|
||||
Log().Debug("Key:%s Val:%s", key, s.Get(key))
|
||||
return s.Get(key)
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,17 @@ func UserLogin(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// UserRegister 用户注册
|
||||
func UserRegister(c *gin.Context) {
|
||||
var service user.UserRegisterService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Register(c)
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// User2FALogin 用户二步验证登录
|
||||
func User2FALogin(c *gin.Context) {
|
||||
var service user.Enable2FA
|
||||
|
|
|
@ -103,6 +103,8 @@ func InitMasterRouter() *gin.Engine {
|
|||
{
|
||||
// 用户登录
|
||||
user.POST("session", controllers.UserLogin)
|
||||
// 用户注册
|
||||
user.POST("", middleware.IsFunctionEnabled("register_enabled"), controllers.UserRegister)
|
||||
// 用户登录
|
||||
user.POST("2fa", controllers.User2FALogin)
|
||||
// 初始化QQ登录
|
||||
|
|
|
@ -51,6 +51,7 @@ func (service *UserLoginService) Login(c *gin.Context) serializer.Response {
|
|||
if model.IsTrueVal(isCaptchaRequired) {
|
||||
// TODO 验证码校验
|
||||
captchaID := util.GetSession(c, "captchaID")
|
||||
util.DeleteSession(c, "captchaID")
|
||||
if captchaID == nil || !base64Captcha.VerifyCaptcha(captchaID.(string), service.CaptchaCode) {
|
||||
return serializer.ParamErr("验证码错误", nil)
|
||||
}
|
||||
|
|
93
service/user/register.go
Normal file
93
service/user/register.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/auth"
|
||||
"github.com/HFO4/cloudreve/pkg/email"
|
||||
"github.com/HFO4/cloudreve/pkg/hashid"
|
||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||
"github.com/HFO4/cloudreve/pkg/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UserRegisterService 管理用户注册的服务
|
||||
type UserRegisterService struct {
|
||||
//TODO 细致调整验证规则
|
||||
UserName string `form:"userName" json:"userName" binding:"required,email"`
|
||||
Password string `form:"Password" json:"Password" binding:"required,min=4,max=64"`
|
||||
CaptchaCode string `form:"captchaCode" json:"captchaCode"`
|
||||
}
|
||||
|
||||
// Register 新用户注册
|
||||
func (service *UserRegisterService) Register(c *gin.Context) serializer.Response {
|
||||
// 相关设定
|
||||
options := model.GetSettingByNames("email_active", "reg_captcha")
|
||||
// 检查验证码
|
||||
isCaptchaRequired := model.IsTrueVal(options["reg_captcha"])
|
||||
if isCaptchaRequired {
|
||||
captchaID := util.GetSession(c, "captchaID")
|
||||
util.DeleteSession(c, "captchaID")
|
||||
if captchaID == nil || !base64Captcha.VerifyCaptcha(captchaID.(string), service.CaptchaCode) {
|
||||
return serializer.ParamErr("验证码错误", nil)
|
||||
}
|
||||
}
|
||||
|
||||
// 相关设定
|
||||
isEmailRequired := model.IsTrueVal(options["email_active"])
|
||||
defaultGroup := model.GetIntSetting("default_group", 2)
|
||||
|
||||
// 创建新的用户对象
|
||||
user := model.NewUser()
|
||||
user.Email = service.UserName
|
||||
user.Nick = strings.Split(service.UserName, "@")[0]
|
||||
user.SetPassword(service.Password)
|
||||
user.Status = model.Active
|
||||
if isEmailRequired {
|
||||
user.Status = model.NotActivicated
|
||||
}
|
||||
user.GroupID = uint(defaultGroup)
|
||||
|
||||
// 创建用户
|
||||
if err := model.DB.Create(&user).Error; err != nil {
|
||||
return serializer.DBErr("此邮箱已被使用", err)
|
||||
}
|
||||
|
||||
// 发送激活邮件
|
||||
if isEmailRequired {
|
||||
|
||||
// 签名激活请求API
|
||||
base := model.GetSiteURL()
|
||||
userID := hashid.HashID(user.ID, hashid.UserID)
|
||||
controller, _ := url.Parse("/api/v3/user/activate/" + userID)
|
||||
activateURL, err := auth.SignURI(auth.General, base.ResolveReference(controller).String(), 86400)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeEncryptError, "无法签名激活URL", err)
|
||||
}
|
||||
|
||||
// 取得签名
|
||||
credential := activateURL.Query().Get("sign")
|
||||
|
||||
// 生成对用户访问的激活地址
|
||||
controller, _ = url.Parse("/activate")
|
||||
finalURL := base.ResolveReference(controller)
|
||||
queries := finalURL.Query()
|
||||
queries.Add("id", userID)
|
||||
queries.Add("sign", credential)
|
||||
finalURL.RawQuery = queries.Encode()
|
||||
|
||||
// 返送激活邮件
|
||||
title, body := email.NewActivationEmail(user.Email,
|
||||
strings.ReplaceAll(finalURL.String(), "/activate", "/#/activate"),
|
||||
)
|
||||
if err := email.Send(user.Email, title, body); err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "无法发送激活邮件", err)
|
||||
}
|
||||
|
||||
return serializer.Response{Code: 203}
|
||||
}
|
||||
|
||||
return serializer.Response{}
|
||||
}
|
Loading…
Add table
Reference in a new issue