From 9d01dce31457d12e4b09700b5d67141f9c6cf9f9 Mon Sep 17 00:00:00 2001 From: saltbo Date: Thu, 8 Jul 2021 12:09:22 +0800 Subject: [PATCH] fix: update the password reset feature for the administrator --- internal/app/api/user.go | 201 +++++++++++++++++++++----------------- internal/pkg/bind/user.go | 6 +- 2 files changed, 117 insertions(+), 90 deletions(-) diff --git a/internal/app/api/user.go b/internal/app/api/user.go index 4f6ac93..65af98b 100644 --- a/internal/app/api/user.go +++ b/internal/app/api/user.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "github.com/saltbo/gopkg/ginutil" _ "github.com/saltbo/gopkg/httputil" + "github.com/saltbo/gopkg/strutil" "github.com/saltbo/zpan/internal/app/dao" "github.com/saltbo/zpan/internal/app/model" @@ -30,18 +31,96 @@ func (rs *UserResource) Register(router *gin.RouterGroup) { router.POST("/users", rs.create) // 账户注册 router.PATCH("/users/:email", rs.patch) // 账户激活、密码重置 - router.GET("/users", rs.findAll) // 查询用户列表,需管理员权限 - router.GET("/users/:username", rs.find) // 查询某一个用户的公开信息 - router.DELETE("/users/:username", rs.remove) // 删除某一个用户 - router.PUT("/users/:username/storage", rs.updateStorage) // 修改某一个用户的存储空间 - router.PUT("/users/:username/password", rs.updatePassword) // 修改某一个用户的用户密码 - router.PUT("/users/:username/status", rs.updateStatus) // 修改某一个用户的状态 + router.GET("/users", rs.findAll) // 查询用户列表,需管理员权限 + router.GET("/users/:username", rs.find) // 查询某一个用户的公开信息 + router.DELETE("/users/:username", rs.remove) // 删除某一个用户 + router.PUT("/users/:username/storage", rs.updateStorage) // 修改某一个用户的存储空间 + router.PUT("/users/:username/password", rs.resetPassword) // 修改某一个用户的用户密码 + router.PUT("/users/:username/status", rs.updateStatus) // 修改某一个用户的状态 router.GET("/user", rs.userMe) // 获取已登录用户的所有信息 router.PUT("/user/profile", rs.updateProfile) // 更新已登录用户个人信息 router.PUT("/user/password", rs.updatePassword) // 修改已登录用户密码 } +// create godoc +// @Tags v1/Users +// @Summary 用户注册 +// @Description 注册一个用户 +// @Accept json +// @Produce json +// @Param body body bind.BodyUser true "参数" +// @Success 200 {object} httputil.JSONResponse{data=model.User} +// @Failure 400 {object} httputil.JSONResponse +// @Failure 500 {object} httputil.JSONResponse +// @Router /v1/users [post] +func (rs *UserResource) create(c *gin.Context) { + p := new(bind.BodyUserCreation) + if err := c.ShouldBindJSON(p); err != nil { + ginutil.JSONBadRequest(c, err) + return + } + + if !authed.IsAdmin(c) && rs.sUser.InviteRequired() && p.Ticket == "" { + ginutil.JSONBadRequest(c, fmt.Errorf("ticket required")) + return + } + + opt := model.NewUserCreateOption() + opt.Roles = model.RoleMember + opt.Ticket = p.Ticket + if authed.IsAdmin(c) { + opt.Roles = p.Roles + opt.StorageMax = p.StorageMax + } + + opt.Origin = ginutil.GetOrigin(c) + if _, err := rs.sUser.Signup(p.Email, p.Password, opt); err != nil { + ginutil.JSONBadRequest(c, err) + return + } + + ginutil.JSON(c) +} + +// patch godoc +// @Tags v1/Users +// @Summary 更新一项用户信息 +// @Description 用于账户激活和密码重置 +// @Accept json +// @Produce json +// @Param email path string true "邮箱" +// @Param body body bind.BodyUserPatch true "参数" +// @Success 200 {object} httputil.JSONResponse +// @Failure 400 {object} httputil.JSONResponse +// @Failure 500 {object} httputil.JSONResponse +// @Router /v1/users/{email} [patch] +func (rs *UserResource) patch(c *gin.Context) { + p := new(bind.BodyUserPatch) + if err := c.ShouldBindJSON(p); err != nil { + ginutil.JSONBadRequest(c, err) + return + } + + // account activate + if p.Activated { + if err := rs.sUser.Active(p.Token); err != nil { + ginutil.JSONServerError(c, err) + return + } + } + + // password reset + if p.Password != "" { + if err := rs.sUser.PasswordReset(p.Token, p.Password); err != nil { + ginutil.JSONServerError(c, err) + return + } + } + + ginutil.JSON(c) +} + // findAll godoc // @Tags v1/Users // @Summary 用户列表 @@ -96,33 +175,6 @@ func (rs *UserResource) find(c *gin.Context) { ginutil.JSONData(c, user.Profile) } -// remove godoc -// @Tags v1/Users -// @Summary 删除某一个用户 -// @Description 删除某一个用户 -// @Accept json -// @Produce json -// @Param username path string true "用户名" -// @Success 200 {object} httputil.JSONResponse -// @Failure 400 {object} httputil.JSONResponse -// @Failure 500 {object} httputil.JSONResponse -// @Router /v1/users/{username} [delete] -func (rs *UserResource) remove(c *gin.Context) { - user, err := rs.dUser.FindByUsername(c.Param("username")) - if err != nil { - ginutil.JSONBadRequest(c, err) - return - } - - if err := rs.dUser.Delete(user); err != nil { - ginutil.JSONServerError(c, err) - return - } - - ginutil.JSON(c) -} - - // updateStorage godoc // @Tags v1/Users // @Summary 修改某一个用户的存储空间 @@ -189,79 +241,61 @@ func (rs *UserResource) updateStatus(c *gin.Context) { ginutil.JSON(c) } -// create godoc +// resetPassword godoc // @Tags v1/Users -// @Summary 用户注册 -// @Description 注册一个用户 +// @Summary 重置某一个用户的密码 +// @Description 重置某一个用户的密码 // @Accept json // @Produce json -// @Param body body bind.BodyUser true "参数" -// @Success 200 {object} httputil.JSONResponse{data=model.User} +// @Param username path string true "用户名" +// @Param body body bind.BodyUserStatus true "参数" +// @Success 200 {object} httputil.JSONResponse // @Failure 400 {object} httputil.JSONResponse // @Failure 500 {object} httputil.JSONResponse -// @Router /v1/users [post] -func (rs *UserResource) create(c *gin.Context) { - p := new(bind.BodyUserCreation) +// @Router /v1/users/{username}/password [put] +func (rs *UserResource) resetPassword(c *gin.Context) { + p := new(bind.BodyUserPasswordReset) if err := c.ShouldBindJSON(p); err != nil { ginutil.JSONBadRequest(c, err) return } - if !authed.IsAdmin(c) && rs.sUser.InviteRequired() && p.Ticket == "" { - ginutil.JSONBadRequest(c, fmt.Errorf("ticket required")) + user, err := rs.dUser.FindByUsername(c.Param("username")) + if err != nil { + ginutil.JSONBadRequest(c, err) return } - opt := model.NewUserCreateOption() - opt.Roles = model.RoleMember - opt.Ticket = p.Ticket - if authed.IsAdmin(c) { - opt.Roles = p.Roles - opt.StorageMax = p.StorageMax - } - - opt.Origin = ginutil.GetOrigin(c) - if _, err := rs.sUser.Signup(p.Email, p.Password, opt); err != nil { - ginutil.JSONBadRequest(c, err) + user.Password = strutil.Md5Hex(p.Password) + if err := rs.dUser.Update(user); err != nil { + ginutil.JSONServerError(c, err) return } ginutil.JSON(c) } -// patch godoc +// remove godoc // @Tags v1/Users -// @Summary 更新一项用户信息 -// @Description 用于账户激活和密码重置 +// @Summary 删除某一个用户 +// @Description 删除某一个用户 // @Accept json // @Produce json -// @Param email path string true "邮箱" -// @Param body body bind.BodyUserPatch true "参数" +// @Param username path string true "用户名" // @Success 200 {object} httputil.JSONResponse // @Failure 400 {object} httputil.JSONResponse // @Failure 500 {object} httputil.JSONResponse -// @Router /v1/users/{email} [patch] -func (rs *UserResource) patch(c *gin.Context) { - p := new(bind.BodyUserPatch) - if err := c.ShouldBindJSON(p); err != nil { +// @Router /v1/users/{username} [delete] +func (rs *UserResource) remove(c *gin.Context) { + user, err := rs.dUser.FindByUsername(c.Param("username")) + if err != nil { ginutil.JSONBadRequest(c, err) return } - // account activate - if p.Activated { - if err := rs.sUser.Active(p.Token); err != nil { - ginutil.JSONServerError(c, err) - return - } - } - - // password reset - if p.Password != "" { - if err := rs.sUser.PasswordReset(p.Token, p.Password); err != nil { - ginutil.JSONServerError(c, err) - return - } + if err := rs.dUser.Delete(user); err != nil { + ginutil.JSONServerError(c, err) + return } ginutil.JSON(c) @@ -297,7 +331,6 @@ func (rs *UserResource) userMe(c *gin.Context) { // @Success 200 {object} httputil.JSONResponse // @Failure 400 {object} httputil.JSONResponse // @Failure 500 {object} httputil.JSONResponse -// @Router /v1/users/{username}/password [put] // @Router /v1/user/password [put] func (rs *UserResource) updatePassword(c *gin.Context) { p := new(bind.BodyUserPassword) @@ -307,16 +340,6 @@ func (rs *UserResource) updatePassword(c *gin.Context) { } uid := authed.UidGet(c) - if username := c.Param("username"); username != "" { - user, err := rs.dUser.FindByUsername(username) - if err != nil { - ginutil.JSONBadRequest(c, err) - return - } - - uid = user.Id - } - if err := rs.sUser.PasswordUpdate(uid, p.OldPassword, p.NewPassword); err != nil { ginutil.JSONServerError(c, err) return @@ -363,4 +386,4 @@ func (rs *UserResource) updateProfile(c *gin.Context) { } ginutil.JSON(c) -} \ No newline at end of file +} diff --git a/internal/pkg/bind/user.go b/internal/pkg/bind/user.go index dcc15bd..37bb5ab 100644 --- a/internal/pkg/bind/user.go +++ b/internal/pkg/bind/user.go @@ -39,5 +39,9 @@ type BodyUserStorage struct { } type BodyUserStatus struct { - Status uint8 `json:"status"` + Status uint8 `json:"status" binding:"required"` +} + +type BodyUserPasswordReset struct { + Password string `json:"password" binding:"required"` }