[feature/backend] update put /users/me endpoint, allow setting username and display name

This commit is contained in:
CDN 2025-02-21 19:57:00 +08:00
parent 1526c27b49
commit 79912925db
Signed by: CDN
GPG key ID: 0C656827F9F80080
4 changed files with 46 additions and 3 deletions

View file

@ -216,14 +216,23 @@ user_me:
schema: schema:
type: object type: object
properties: properties:
username:
type: string
minLength: 3
maxLength: 32
display_name:
type: string
maxLength: 64
email: email:
type: string type: string
format: email format: email
current_password: current_password:
type: string type: string
description: 当修改密码时必填
new_password: new_password:
type: string type: string
minLength: 8 minLength: 8
description: 新密码,如果要修改密码则必填
responses: responses:
'200': '200':
description: 用户信息更新成功 description: 用户信息更新成功

View file

@ -11,6 +11,7 @@ import (
) )
type UpdateCurrentUserRequest struct { type UpdateCurrentUserRequest struct {
Username string `json:"username,omitempty" binding:"omitempty,min=3,max=32"`
Email string `json:"email,omitempty" binding:"omitempty,email"` Email string `json:"email,omitempty" binding:"omitempty,email"`
CurrentPassword string `json:"current_password,omitempty"` CurrentPassword string `json:"current_password,omitempty"`
NewPassword string `json:"new_password,omitempty" binding:"omitempty,min=8"` NewPassword string `json:"new_password,omitempty" binding:"omitempty,min=8"`
@ -211,12 +212,20 @@ func (h *Handler) GetCurrentUser(c *gin.Context) {
// UpdateCurrentUser updates the current user's information // UpdateCurrentUser updates the current user's information
func (h *Handler) UpdateCurrentUser(c *gin.Context) { func (h *Handler) UpdateCurrentUser(c *gin.Context) {
// 从上下文中获取用户ID由认证中间件设置 // 从上下文中获取用户ID由认证中间件设置
userID, exists := c.Get("user_id") userIDStr, exists := c.Get("user_id")
if !exists { if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return return
} }
// 将用户ID转换为整数
userID, err := strconv.Atoi(userIDStr.(string))
if err != nil {
log.Error().Err(err).Msg("Failed to convert user ID to integer")
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user ID format"})
return
}
var req UpdateCurrentUserRequest var req UpdateCurrentUserRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
@ -231,20 +240,25 @@ func (h *Handler) UpdateCurrentUser(c *gin.Context) {
} }
// 验证当前密码 // 验证当前密码
if err := h.service.VerifyPassword(c.Request.Context(), userID.(int), req.CurrentPassword); err != nil { if err := h.service.VerifyPassword(c.Request.Context(), userID, req.CurrentPassword); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid current password"}) c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid current password"})
return return
} }
} }
// 更新用户信息 // 更新用户信息
user, err := h.service.UpdateUser(c.Request.Context(), userID.(int), &types.UpdateUserInput{ user, err := h.service.UpdateUser(c.Request.Context(), userID, &types.UpdateUserInput{
Username: req.Username,
Email: req.Email, Email: req.Email,
Password: req.NewPassword, Password: req.NewPassword,
DisplayName: req.DisplayName, DisplayName: req.DisplayName,
}) })
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to update user") log.Error().Err(err).Msg("Failed to update user")
if err.Error() == "username already taken" {
c.JSON(http.StatusConflict, gin.H{"error": "Username already taken"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user information"}) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user information"})
return return
} }

View file

@ -40,6 +40,25 @@ func (s *serviceImpl) UpdateUser(ctx context.Context, userID int, input *types.U
// Start building the update // Start building the update
update := s.client.User.UpdateOneID(userID) update := s.client.User.UpdateOneID(userID)
// Update username if provided
if input.Username != "" {
// Check if username is already taken
exists, err := s.client.User.Query().
Where(user.And(
user.UsernameEQ(input.Username),
user.IDNEQ(userID),
)).
Exist(ctx)
if err != nil {
log.Error().Err(err).Msg("Failed to check username availability")
return nil, fmt.Errorf("failed to check username availability: %w", err)
}
if exists {
return nil, fmt.Errorf("username already taken")
}
update.SetUsername(input.Username)
}
// Update email if provided // Update email if provided
if input.Email != "" { if input.Email != "" {
update.SetEmail(input.Email) update.SetEmail(input.Email)

View file

@ -2,6 +2,7 @@ package types
// UpdateUserInput defines the input for updating a user // UpdateUserInput defines the input for updating a user
type UpdateUserInput struct { type UpdateUserInput struct {
Username string
Email string Email string
Password string Password string
Role string Role string