mirror of
https://github.com/XShengTech/MEGREZ.git
synced 2026-05-03 13:02:38 +00:00
[Feat] ✨ Add Email Verify API & Pages #15
This commit is contained in:
@@ -20,7 +20,7 @@ func detailHandler(ctx iris.Context) {
|
||||
user := models.Users{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Select("id", "username", "email", "role", "balance", "created_at").First(&user)
|
||||
result := database.DB.Select("id", "username", "email", "role", "verify", "balance", "created_at").First(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("detail user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserDetailError, iris.StatusInternalServerError)
|
||||
|
||||
@@ -42,7 +42,7 @@ func listHandler(ctx iris.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
result := database.DB.Limit(limit).Offset(offset).Select("id", "username", "email", "role", "balance", "created_at").Order("id").Find(&users)
|
||||
result := database.DB.Limit(limit).Offset(offset).Select("id", "username", "email", "role", "verify", "balance", "created_at").Order("id").Find(&users)
|
||||
if result.Error != nil {
|
||||
l.Error("list users error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserListError, iris.StatusInternalServerError)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
type modifyReqStruct struct {
|
||||
Password *string `json:"password"`
|
||||
Role *int `json:"role"`
|
||||
Verify *bool `json:"verify"`
|
||||
}
|
||||
|
||||
func modifyHandler(ctx iris.Context) {
|
||||
@@ -55,6 +56,10 @@ func modifyHandler(ctx iris.Context) {
|
||||
user.Role = *req.Role
|
||||
}
|
||||
|
||||
if req.Verify != nil {
|
||||
user.Verify = *req.Verify
|
||||
}
|
||||
|
||||
result = database.DB.Save(&user)
|
||||
if result.Error != nil {
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
|
||||
@@ -42,6 +42,10 @@ const (
|
||||
CodeAdminUserDeleteError ResCode = 2013
|
||||
CodeAdminUserInstanceNoEmpty ResCode = 2014
|
||||
CodeAdminUserModifyError ResCode = 2015
|
||||
|
||||
CodeUserAlreadyVerified ResCode = 3001
|
||||
CodeUserVerifyInvalid ResCode = 3002
|
||||
CodePasswordNotMatch ResCode = 3003
|
||||
)
|
||||
|
||||
var codeMsgMap = map[ResCode]string{
|
||||
@@ -84,4 +88,8 @@ var codeMsgMap = map[ResCode]string{
|
||||
CodeAdminUserDeleteError: "delete user error",
|
||||
CodeAdminUserModifyError: "modify user error",
|
||||
CodeAdminUserInstanceNoEmpty: "user instances not empty",
|
||||
|
||||
CodeUserAlreadyVerified: "user already verified",
|
||||
CodeUserVerifyInvalid: "email verify error",
|
||||
CodePasswordNotMatch: "password not match",
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ func loginHandler(ctx iris.Context) {
|
||||
Email: user.Email,
|
||||
Role: user.Role,
|
||||
Balance: user.Balance,
|
||||
Verify: user.Verify,
|
||||
}
|
||||
|
||||
middleware.Result(ctx, profile)
|
||||
|
||||
@@ -14,6 +14,7 @@ type profile struct {
|
||||
Email string `json:"email"`
|
||||
Role int `json:"role"`
|
||||
Balance float64 `json:"balance"`
|
||||
Verify bool `json:"verify"`
|
||||
}
|
||||
|
||||
func profileHandler(ctx iris.Context) {
|
||||
@@ -40,6 +41,7 @@ func profileHandler(ctx iris.Context) {
|
||||
Email: user.Email,
|
||||
Role: user.Role,
|
||||
Balance: user.Balance,
|
||||
Verify: user.Verify,
|
||||
}
|
||||
|
||||
middleware.Result(ctx, profile)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
type resetPasswordStruct struct {
|
||||
OldPassword string `json:"old_password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
RePassword string `json:"re_password"`
|
||||
}
|
||||
|
||||
func resetPasswordHandler(ctx iris.Context) {
|
||||
@@ -22,12 +23,17 @@ func resetPasswordHandler(ctx iris.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var resetPassword resetPasswordStruct
|
||||
if err := ctx.ReadJSON(&resetPassword); err != nil {
|
||||
var req resetPasswordStruct
|
||||
if err := ctx.ReadJSON(&req); err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.NewPassword != req.RePassword {
|
||||
middleware.Error(ctx, middleware.CodePasswordNotMatch, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: uint(userId),
|
||||
}
|
||||
@@ -38,12 +44,12 @@ func resetPasswordHandler(ctx iris.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !user.CheckPassword(resetPassword.OldPassword) {
|
||||
if !user.CheckPassword(req.OldPassword) {
|
||||
middleware.Error(ctx, middleware.CodePasswordError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user.Password = user.PasswordHash(resetPassword.NewPassword)
|
||||
user.Password = user.PasswordHash(req.NewPassword)
|
||||
result = database.DB.Save(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("save user error: %v", result.Error)
|
||||
|
||||
@@ -25,6 +25,8 @@ func InitUser(party router.Party) {
|
||||
party.Post("/register", registerHandler)
|
||||
party.Get("/profile", middleware.AuthCheck, profileHandler)
|
||||
party.Post("/resetPassword", middleware.AuthCheck, resetPasswordHandler)
|
||||
party.Get("/verify/{code:string}", verifyHandler)
|
||||
party.Post("/verify", middleware.AuthCheck, verifySendHandler)
|
||||
|
||||
servers.InitServers(party.Party("/servers"))
|
||||
instances.InitInstances(party.Party("/instances"))
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func verifyHandler(ctx iris.Context) {
|
||||
l.SetFunction("verifyHandler")
|
||||
|
||||
code := ctx.Params().GetString("code")
|
||||
|
||||
rdb := redis.RawDB
|
||||
v := rdb.Get(ctx, verifyRedisKeyPrefix+code)
|
||||
|
||||
if v.Err() != nil {
|
||||
middleware.Error(ctx, middleware.CodeUserVerifyInvalid, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
r := rdb.Del(ctx, verifyRedisKeyPrefix+code)
|
||||
if r.Err() != nil {
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
l.Error("delete redis verify code error: %v", r.Err())
|
||||
return
|
||||
}
|
||||
|
||||
email := v.Val()
|
||||
l.Debug("verify email: %s", email)
|
||||
user := models.Users{
|
||||
Email: email,
|
||||
}
|
||||
result := database.DB.Where(&user).First(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("get user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeUserVerifyInvalid, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
result = database.DB.Model(&user).Update("verify", true)
|
||||
if result.Error != nil {
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
l.Error("update user verify status Error: %v", result.Error)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"megrez/libs/crypto"
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/config"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"megrez/services/smtp"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
const verifyRedisKeyPrefix = "verify:user:"
|
||||
const verifyUrlPrefix = "/verify/"
|
||||
const verifyTitle = "邮箱验证"
|
||||
const verifyHTMLFormat = `
|
||||
<div>
|
||||
<table cellpadding="0" align="center" style="overflow:hidden;background:#fff;margin:0 auto;text-align:left;position:relative;font-size:14px; font-family:'lucida Grande',Verdana;line-height:1.5;box-shadow:0 0 3px #ccc;border:1px solid #ccc;border-radius:5px;border-collapse:collapse;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th valign="middle" style="height:38px;color:#fff; font-size:14px;line-height:38px; font-weight:bold;text-align:left;padding:10px 24px 6px; border-bottom:1px solid #467ec3;background:#518bcb;border-radius:5px 5px 0 0;">
|
||||
MEGREZ 天权算能聚联计算平台</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div style="padding:20px 35px 40px;">
|
||||
<h2 style="font-weight:bold;margin-bottom:5px;font-size:14px;">Hello, %s:</h2>
|
||||
<p style="margin-top:20px">
|
||||
请在15分钟内点击链接: <a href="%s">%s</a> 进行邮箱验证操作,十五分钟后该链接将会失效.
|
||||
</p>
|
||||
<p style="margin-top:20px">
|
||||
如果您有任何问题,请联系系统管理员以获得更多信息与支持。
|
||||
</p>
|
||||
<p style="margin-left:2em;"></p>
|
||||
<p style="text-indent:0;text-align:right;">MEGREZ 天权算能聚联计算平台</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`
|
||||
|
||||
func verifySendHandler(ctx iris.Context) {
|
||||
l.SetFunction("verifySendHandler")
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: uint(userId),
|
||||
}
|
||||
result := database.DB.First(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("get user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeUserNotExist, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if user.Verify {
|
||||
middleware.Error(ctx, middleware.CodeUserAlreadyVerified, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rdb := redis.RawDB
|
||||
|
||||
verifyUrl := crypto.Hex(32)
|
||||
rdb.Set(ctx, verifyRedisKeyPrefix+verifyUrl, user.Email, 15*time.Minute)
|
||||
|
||||
verifyUrl = config.GetSystemBaseUrl() + verifyUrlPrefix + verifyUrl
|
||||
err = smtp.Send(user.Email, verifyTitle, fmt.Sprintf(verifyHTMLFormat, user.Username, verifyUrl, verifyUrl))
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
l.Error("Send SMTP Error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
Reference in New Issue
Block a user