Feat: user register / send activate email

pull/247/head
HFO4 4 years ago
parent 7c07b623f6
commit 81d6988a50

@ -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)
}

@ -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…
Cancel
Save