Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update user info && fix some errors #15

Merged
merged 5 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions internal/common/dao/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ func CreateUser(user *model.User) (err error) {
return err
}

// SetUserPassword 修改用户密码
func SetUserPassword(user *model.User, newpass string) (err error) {
// SetUserPassword 设置用户密码
func SetUserPassword(user *model.User, newPassword string) (err error) {
u := query.User
password, err := bcrypt.GenerateFromPassword([]byte(newpass), bcrypt.DefaultCost)
password, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
if err != nil {
return err
}
Expand All @@ -27,6 +27,16 @@ func SetUserPassword(user *model.User, newpass string) (err error) {
return err
}

// UpdateUserDataByUserID 根据 map 更新用户信息,map 中的 key 为字段名
func UpdateUserDataByUserID(userID int32, maps map[string]interface{}) (err error) {
u := query.User
_, err = u.Where(u.UserID.Eq(userID)).Updates(maps)
if err != nil {
return err
}
return err
}

// GetUserByEmail 根据 email 获取用户
func GetUserByEmail(email string) (user *model.User, err error) {
q := query.User
Expand Down
13 changes: 8 additions & 5 deletions internal/router/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func NewAPI() *gin.Engine {
jwt.RequireAuth(cache.Clients[cache.JWTBlacklist], true), // 把 token 拉黑
user_service.Logout,
)
// 修改密码
user.POST("password/reset",
jwt.RequireAuth(cache.Clients[cache.JWTBlacklist], false),
user_service.ResetPassword)
// 用户信息
user.GET("profile/me",
jwt.RequireAuth(cache.Clients[cache.JWTBlacklist], false),
Expand All @@ -51,11 +55,10 @@ func NewAPI() *gin.Engine {
middleware_cache.Response(cache.Clients[cache.RespCache], 1*time.Minute),
user_service.ProfileOthers,
)

// 修改密码
user.POST("password/reset",
jwt.RequireAuth(cache.Clients[cache.JWTBlacklist], true), // 把 token 拉黑
user_service.ResetPassword)
// 用户信息更新
user.POST("profile/update",
jwt.RequireAuth(cache.Clients[cache.JWTBlacklist], false),
user_service.ProfileUpdate)
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/service/user/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type LoginResponse struct {
func Login(c *gin.Context) {
var req LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.AbortWithMsg(c, "invalid request")
util.AbortWithMsg(c, "invalid request: "+err.Error())
return
}

Expand Down
8 changes: 2 additions & 6 deletions internal/service/user/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ import (

// Logout 用户登出 (POST /logout)
func Logout(c *gin.Context) {
user, err := util.GetUserIDFromGinContext(c)
if err != nil {
util.AbortWithMsg(c, "Please login first")
return
}
userID, _ := util.GetUserIDFromGinContext(c)

util.OKWithMsg(c, "Logout success")

log.Logger.Info("Logout success: " + util.StructToString(user))
log.Logger.Info("Logout success, user ID: " + util.StructToString(userID))
}
66 changes: 28 additions & 38 deletions internal/service/user/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ type ProfileResponse struct {
Avatar string `json:"avatar"`
Background string `json:"background"`
CreatedAt string `json:"created_at"`
Email string `json:"email"`
Experience string `json:"experience"`
Inviter string `json:"inviter"`
Email *string `json:"email,omitempty"`
Experience *int32 `json:"experience,omitempty"`
Inviter *int32 `json:"inviter,omitempty"`
LastActive string `json:"last_active"`
Private bool `json:"private"`
Roles []string `json:"roles,omitempty"`
Expand All @@ -25,16 +25,12 @@ type ProfileResponse struct {
}

type ProfileOthersRequest struct {
UserId int32 `form:"user_id" binding:"required"`
UserID int32 `form:"user_id" binding:"required"`
}

// ProfileMe 获取用户自己的信息 (GET /profile/me)
func ProfileMe(c *gin.Context) {
userID, err := util.GetUserIDFromGinContext(c)
if err != nil {
util.AbortWithMsg(c, "Please login first")
return
}
userID, _ := util.GetUserIDFromGinContext(c)

user, err := dao.GetUserByID(userID)
if err != nil {
Expand All @@ -52,9 +48,9 @@ func ProfileMe(c *gin.Context) {
Avatar: user.Avatar,
Background: user.Background,
CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
Email: user.Email,
Experience: strconv.Itoa(int(user.Experience)),
Inviter: strconv.Itoa(int(user.Inviter)),
Email: &user.Email,
Experience: &user.Experience,
Inviter: &user.Inviter,
LastActive: user.LastActive.Format("2006-01-02 15:04:05"),
Private: user.Private,
Roles: roles,
Expand All @@ -71,29 +67,20 @@ func ProfileOthers(c *gin.Context) {
// 绑定参数
var req ProfileOthersRequest
if err := c.ShouldBindQuery(&req); err != nil {
util.AbortWithMsg(c, "invalid request")
return
}
// 鉴权
userID, err := util.GetUserIDFromGinContext(c)
if err != nil {
util.AbortWithMsg(c, "Please login first")
return
}
// 仅用于鉴权不使用
_, err = dao.GetUserByID(userID)
if err != nil {
util.AbortWithMsg(c, "User not found")
util.AbortWithMsg(c, "invalid request: "+err.Error())
return
}

userID, _ := util.GetUserIDFromGinContext(c)

// 获取信息
user, err := dao.GetUserByID(req.UserId)
user, err := dao.GetUserByID(req.UserID)
if err != nil {
util.AbortWithMsg(c, "User not found")
return
}

roles, err := dao.GetUserRolesByID(userID)
roles, err := dao.GetUserRolesByID(req.UserID)
if err != nil {
log.Logger.Info("Failed to get user roles: " + err.Error())
roles = []string{}
Expand All @@ -104,14 +91,14 @@ func ProfileOthers(c *gin.Context) {
util.OKWithData(c, ProfileResponse{
Avatar: user.Avatar,
Background: user.Background,
CreatedAt: "",
Email: "",
Experience: "",
Inviter: "",
LastActive: "",
Private: user.Private,
CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
Email: nil,
Experience: nil,
Inviter: nil,
LastActive: user.LastActive.Format("2006-01-02 15:04:05"),
Private: true,
Roles: nil,
Signature: "",
Signature: user.Signature,
UserID: user.UserID,
Username: user.Username,
})
Expand All @@ -121,15 +108,18 @@ func ProfileOthers(c *gin.Context) {
Avatar: user.Avatar,
Background: user.Background,
CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
Email: user.Email,
Experience: strconv.Itoa(int(user.Experience)),
Inviter: strconv.Itoa(int(user.Inviter)),
Email: &user.Email,
Experience: &user.Experience,
Inviter: &user.Inviter,
LastActive: user.LastActive.Format("2006-01-02 15:04:05"),
Private: user.Private,
Private: false,
Roles: roles,
Signature: user.Signature,
UserID: user.UserID,
Username: user.Username,
})
}

log.Logger.Info("Get user profile success: " + strconv.Itoa(int(req.UserID)) +
", by user ID: " + strconv.Itoa(int(userID)))
}
73 changes: 73 additions & 0 deletions internal/service/user/profile_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package user

import (
"strconv"

"github.com/TensoRaws/NuxBT-Backend/internal/common/dao"
"github.com/TensoRaws/NuxBT-Backend/module/log"
"github.com/TensoRaws/NuxBT-Backend/module/util"
"github.com/gin-gonic/gin"
)

type ProfileUpdateRequest struct {
Avatar *string `json:"avatar" binding:"omitempty"`
Background *string `json:"background" binding:"omitempty"`
Email *string `json:"email" binding:"omitempty,email"`
Private *bool `json:"private" binding:"omitempty"`
Signature *string `json:"signature" binding:"omitempty"`
Username *string `json:"username" binding:"omitempty"`
}

// ProfileUpdate 用户信息更新 (POST /profile/update)
func ProfileUpdate(c *gin.Context) {
// 参数绑定
var req ProfileUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.AbortWithMsg(c, "invalid request: "+err.Error())
return
}

userID, _ := util.GetUserIDFromGinContext(c)

// 准备更新数据
updates := make(map[string]interface{})

if req.Private != nil {
updates["private"] = req.Private
}

if req.Username != nil && *req.Username != "" {
err := util.CheckUsername(*req.Username)
if err != nil {
util.AbortWithMsg(c, "invalid username: "+err.Error())
return
}
updates["username"] = *req.Username
}

if req.Email != nil {
updates["email"] = *req.Email
}

if req.Avatar != nil {
updates["avatar"] = *req.Avatar
}

if req.Signature != nil {
updates["signature"] = *req.Signature
}

if req.Background != nil {
updates["background"] = *req.Background
}
// 执行更新
err := dao.UpdateUserDataByUserID(userID, updates)
if err != nil {
util.AbortWithMsg(c, "update failed: "+err.Error())
return
}

util.OKWithMsg(c, "update success")

log.Logger.Info("update user profile success: " + strconv.Itoa(int(userID)))
}
16 changes: 10 additions & 6 deletions internal/service/user/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ type RegisterDataResponse struct {
func Register(c *gin.Context) {
var req RegisterRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.AbortWithMsg(c, "invalid request")
util.AbortWithMsg(c, "invalid request: "+err.Error())
return
}

err := util.CheckUsername(req.Username)
if err != nil {
util.AbortWithMsg(c, "invalid username: "+err.Error())
return
}

Expand All @@ -42,10 +48,8 @@ func Register(c *gin.Context) {
return
}
} else {
// 有邀请码注册,检查邀请码是否有效
// do something
// 未实现
// OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
// TODO: 邀请码功能, 有邀请码注册,检查邀请码是否有效

log.Logger.Info("invitation code: " + *req.InvitationCode)
}
password, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
Expand All @@ -62,7 +66,7 @@ func Register(c *gin.Context) {
LastActive: time.Now(),
})
if err != nil {
util.AbortWithMsg(c, "failed to register: ")
util.AbortWithMsg(c, "failed to register: "+err.Error())
log.Logger.Error("failed to register: " + err.Error())
return
}
Expand Down
9 changes: 2 additions & 7 deletions internal/service/user/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@ func ResetPassword(c *gin.Context) {
// 绑定参数
var req ResetPasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.AbortWithMsg(c, "invalid request")
util.AbortWithMsg(c, "invalid request: "+err.Error())
return
}

// 鉴权
userID, err := util.GetUserIDFromGinContext(c)
if err != nil {
util.AbortWithMsg(c, "Please login first")
return
}
userID, _ := util.GetUserIDFromGinContext(c)

user, err := dao.GetUserByID(userID)
if err != nil {
Expand Down
25 changes: 25 additions & 0 deletions module/util/username.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package util

import "fmt"

func CheckUsername(username string) error {
l := len([]rune(username))
if l > 20 {
return fmt.Errorf("username too long")
}
if l < 2 {
return fmt.Errorf("username too short")
}
if username == "" {
return fmt.Errorf("username cannot be empty")
}
adminWords := []string{"admin", "root", "administrator", "管理员", "超级管理员", "版主", "站长", "moderator"}
for _, word := range adminWords {
if username == word {
return fmt.Errorf("username cannot be %s", word)
}
}
// TODO: more checks,如检查敏感词

return nil
}
Loading