feat: Add public user information retrieval endpoint
- Introduced a new endpoint to fetch public user information without authentication. - Implemented UserToPublicUserInfo function to format user data for the response. - Updated UserService interface and user service implementation to support fetching users by username. - Enhanced user handler to validate input parameters and check user status before responding.
This commit is contained in:
@@ -62,6 +62,19 @@ func UserToUserInfo(user *model.User) *types.UserInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// UserToPublicUserInfo 将 User 模型转换为 PublicUserInfo 响应
|
||||
func UserToPublicUserInfo(user *model.User) *types.PublicUserInfo {
|
||||
return &types.PublicUserInfo{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Avatar: user.Avatar,
|
||||
Points: user.Points,
|
||||
Role: user.Role,
|
||||
Status: user.Status,
|
||||
CreatedAt: user.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// ProfileToProfileInfo 将 Profile 模型转换为 ProfileInfo 响应
|
||||
func ProfileToProfileInfo(profile *model.Profile) *types.ProfileInfo {
|
||||
return &types.ProfileInfo{
|
||||
|
||||
@@ -93,6 +93,10 @@ func registerAuthRoutes(v1 *gin.RouterGroup, h *AuthHandler) {
|
||||
|
||||
// registerUserRoutes 注册用户路由
|
||||
func registerUserRoutes(v1 *gin.RouterGroup, h *UserHandler, jwtService *auth.JWTService) {
|
||||
// 公开用户信息路由(无需认证)
|
||||
v1.GET("/users/public", h.GetPublicInfo)
|
||||
|
||||
// 需要认证的用户路由
|
||||
userGroup := v1.Group("/user")
|
||||
userGroup.Use(middleware.AuthMiddleware(jwtService))
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"carrotskin/internal/container"
|
||||
"carrotskin/internal/model"
|
||||
"carrotskin/internal/service"
|
||||
"carrotskin/internal/types"
|
||||
|
||||
@@ -315,3 +316,55 @@ func (h *UserHandler) ResetYggdrasilPassword(c *gin.Context) {
|
||||
h.logger.Info("Yggdrasil密码重置成功", zap.Int64("userId", userID))
|
||||
RespondSuccess(c, gin.H{"password": newPassword})
|
||||
}
|
||||
|
||||
// GetPublicInfo 获取用户公开信息
|
||||
// @Summary 获取用户公开信息
|
||||
// @Description 根据用户名或用户ID获取用户的公开信息(不包含敏感信息如邮箱)
|
||||
// @Tags user
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param username query string false "用户名"
|
||||
// @Param id query int false "用户ID"
|
||||
// @Success 200 {object} model.Response{data=types.PublicUserInfo} "获取成功"
|
||||
// @Failure 400 {object} model.ErrorResponse "参数错误"
|
||||
// @Failure 404 {object} model.ErrorResponse "用户不存在"
|
||||
// @Router /api/v1/users/public [get]
|
||||
func (h *UserHandler) GetPublicInfo(c *gin.Context) {
|
||||
username := c.Query("username")
|
||||
idStr := c.Query("id")
|
||||
|
||||
// 至少需要提供一个参数
|
||||
if username == "" && idStr == "" {
|
||||
RespondBadRequest(c, "必须提供用户名或用户ID", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
var err error
|
||||
|
||||
// 优先使用用户名查询
|
||||
if username != "" {
|
||||
user, err = h.container.UserService.GetByUsername(c.Request.Context(), username)
|
||||
} else {
|
||||
// 使用用户ID查询
|
||||
id := parseIntWithDefault(idStr, 0)
|
||||
if id == 0 {
|
||||
RespondBadRequest(c, "无效的用户ID", nil)
|
||||
return
|
||||
}
|
||||
user, err = h.container.UserService.GetByID(c.Request.Context(), int64(id))
|
||||
}
|
||||
|
||||
if err != nil || user == nil {
|
||||
RespondNotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if user.Status != 1 {
|
||||
RespondNotFound(c, "用户不可用")
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, UserToPublicUserInfo(user))
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ type UserService interface {
|
||||
// 用户查询
|
||||
GetByID(ctx context.Context, id int64) (*model.User, error)
|
||||
GetByEmail(ctx context.Context, email string) (*model.User, error)
|
||||
GetByUsername(ctx context.Context, username string) (*model.User, error)
|
||||
|
||||
// 用户更新
|
||||
UpdateInfo(ctx context.Context, user *model.User) error
|
||||
|
||||
@@ -199,6 +199,14 @@ func (s *userService) GetByEmail(ctx context.Context, email string) (*model.User
|
||||
}, s.cache.Policy.UserEmailTTL)
|
||||
}
|
||||
|
||||
func (s *userService) GetByUsername(ctx context.Context, username string) (*model.User, error) {
|
||||
// 使用 Cached 装饰器自动处理缓存
|
||||
cacheKey := s.cacheKeys.UserByUsername(username)
|
||||
return database.Cached(ctx, s.cache, cacheKey, func() (*model.User, error) {
|
||||
return s.userRepo.FindByUsername(ctx, username)
|
||||
}, s.cache.Policy.UserTTL)
|
||||
}
|
||||
|
||||
func (s *userService) UpdateInfo(ctx context.Context, user *model.User) error {
|
||||
err := s.userRepo.Update(ctx, user)
|
||||
if err != nil {
|
||||
|
||||
@@ -110,6 +110,18 @@ type UserInfo struct {
|
||||
UpdatedAt time.Time `json:"updated_at" example:"2025-10-01T10:00:00Z"`
|
||||
}
|
||||
|
||||
// PublicUserInfo 用户公开信息
|
||||
// @Description 用户公开信息(不包含敏感信息如邮箱)
|
||||
type PublicUserInfo struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Username string `json:"username" example:"testuser"`
|
||||
Avatar string `json:"avatar" example:"https://example.com/avatar.png"`
|
||||
Points int `json:"points" example:"100"`
|
||||
Role string `json:"role" example:"user"`
|
||||
Status int16 `json:"status" example:"1"`
|
||||
CreatedAt time.Time `json:"created_at" example:"2025-10-01T10:00:00Z"`
|
||||
}
|
||||
|
||||
// TextureType 材质类型
|
||||
type TextureType string
|
||||
|
||||
|
||||
Reference in New Issue
Block a user