diff --git a/api/schemas/paths/users.yaml b/api/schemas/paths/users.yaml index 897adad..da741eb 100644 --- a/api/schemas/paths/users.yaml +++ b/api/schemas/paths/users.yaml @@ -216,14 +216,23 @@ user_me: schema: type: object properties: + username: + type: string + minLength: 3 + maxLength: 32 + display_name: + type: string + maxLength: 64 email: type: string format: email current_password: type: string + description: 当修改密码时必填 new_password: type: string minLength: 8 + description: 新密码,如果要修改密码则必填 responses: '200': description: 用户信息更新成功 diff --git a/backend/internal/handler/user.go b/backend/internal/handler/user.go index b96603b..bd9f8fb 100644 --- a/backend/internal/handler/user.go +++ b/backend/internal/handler/user.go @@ -11,6 +11,7 @@ import ( ) type UpdateCurrentUserRequest struct { + Username string `json:"username,omitempty" binding:"omitempty,min=3,max=32"` Email string `json:"email,omitempty" binding:"omitempty,email"` CurrentPassword string `json:"current_password,omitempty"` 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 func (h *Handler) UpdateCurrentUser(c *gin.Context) { // 从上下文中获取用户ID(由认证中间件设置) - userID, exists := c.Get("user_id") + userIDStr, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) 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 if err := c.ShouldBindJSON(&req); err != nil { 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"}) 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, Password: req.NewPassword, DisplayName: req.DisplayName, }) if err != nil { 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"}) return } diff --git a/backend/internal/service/user.go b/backend/internal/service/user.go index 0ae658b..9d1d015 100644 --- a/backend/internal/service/user.go +++ b/backend/internal/service/user.go @@ -40,6 +40,25 @@ func (s *serviceImpl) UpdateUser(ctx context.Context, userID int, input *types.U // Start building the update 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 if input.Email != "" { update.SetEmail(input.Email) diff --git a/backend/internal/types/user.go b/backend/internal/types/user.go index 1eef0b6..45a0b9e 100644 --- a/backend/internal/types/user.go +++ b/backend/internal/types/user.go @@ -2,6 +2,7 @@ package types // UpdateUserInput defines the input for updating a user type UpdateUserInput struct { + Username string Email string Password string Role string