Files
tyapi-server/internal/domains/user/handlers/user_handler.go

456 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handlers
import (
"strconv"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"tyapi-server/internal/domains/user/dto"
"tyapi-server/internal/domains/user/services"
"tyapi-server/internal/shared/interfaces"
"tyapi-server/internal/shared/middleware"
)
// UserHandler 用户HTTP处理器
type UserHandler struct {
userService *services.UserService
response interfaces.ResponseBuilder
validator interfaces.RequestValidator
logger *zap.Logger
jwtAuth *middleware.JWTAuthMiddleware
}
// NewUserHandler 创建用户处理器
func NewUserHandler(
userService *services.UserService,
response interfaces.ResponseBuilder,
validator interfaces.RequestValidator,
logger *zap.Logger,
jwtAuth *middleware.JWTAuthMiddleware,
) *UserHandler {
return &UserHandler{
userService: userService,
response: response,
validator: validator,
logger: logger,
jwtAuth: jwtAuth,
}
}
// GetPath 返回处理器路径
func (h *UserHandler) GetPath() string {
return "/users"
}
// GetMethod 返回HTTP方法
func (h *UserHandler) GetMethod() string {
return "GET" // 主要用于列表,具体方法在路由注册时指定
}
// GetMiddlewares 返回中间件
func (h *UserHandler) GetMiddlewares() []gin.HandlerFunc {
return []gin.HandlerFunc{
// 这里可以添加特定的中间件
}
}
// Handle 主处理函数(用于列表)
func (h *UserHandler) Handle(c *gin.Context) {
h.List(c)
}
// RequiresAuth 是否需要认证
func (h *UserHandler) RequiresAuth() bool {
return true
}
// GetPermissions 获取所需权限
func (h *UserHandler) GetPermissions() []string {
return []string{"user:read"}
}
// REST操作实现
// Create 创建用户
func (h *UserHandler) Create(c *gin.Context) {
var req dto.CreateUserRequest
// 验证请求体
if err := h.validator.BindAndValidate(c, &req); err != nil {
return // 响应已在验证器中处理
}
// 创建用户
user, err := h.userService.Create(c.Request.Context(), &req)
if err != nil {
h.logger.Error("Failed to create user", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
// 返回响应
response := dto.FromEntity(user)
h.response.Created(c, response, "User created successfully")
}
// GetByID 根据ID获取用户
func (h *UserHandler) GetByID(c *gin.Context) {
id := c.Param("id")
if id == "" {
h.response.BadRequest(c, "User ID is required")
return
}
// 获取用户
user, err := h.userService.GetByID(c.Request.Context(), id)
if err != nil {
h.logger.Error("Failed to get user", zap.Error(err))
h.response.NotFound(c, "User not found")
return
}
// 返回响应
response := dto.FromEntity(user)
h.response.Success(c, response)
}
// Update 更新用户
func (h *UserHandler) Update(c *gin.Context) {
id := c.Param("id")
if id == "" {
h.response.BadRequest(c, "User ID is required")
return
}
var req dto.UpdateUserRequest
// 验证请求体
if err := h.validator.BindAndValidate(c, &req); err != nil {
return
}
// 更新用户
user, err := h.userService.Update(c.Request.Context(), id, &req)
if err != nil {
h.logger.Error("Failed to update user", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
// 返回响应
response := dto.FromEntity(user)
h.response.Success(c, response, "User updated successfully")
}
// Delete 删除用户
func (h *UserHandler) Delete(c *gin.Context) {
id := c.Param("id")
if id == "" {
h.response.BadRequest(c, "User ID is required")
return
}
// 删除用户
if err := h.userService.Delete(c.Request.Context(), id); err != nil {
h.logger.Error("Failed to delete user", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
// 返回响应
h.response.Success(c, nil, "User deleted successfully")
}
// List 获取用户列表
func (h *UserHandler) List(c *gin.Context) {
var req dto.UserListRequest
// 验证查询参数
if err := h.validator.ValidateQuery(c, &req); err != nil {
return
}
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 20
}
// 构建查询选项
options := interfaces.ListOptions{
Page: req.Page,
PageSize: req.PageSize,
Sort: req.Sort,
Order: req.Order,
Search: req.Search,
Filters: req.Filters,
}
// 获取用户列表
users, err := h.userService.List(c.Request.Context(), options)
if err != nil {
h.logger.Error("Failed to get user list", zap.Error(err))
h.response.InternalError(c, "Failed to get user list")
return
}
// 获取总数
countOptions := interfaces.CountOptions{
Search: req.Search,
Filters: req.Filters,
}
total, err := h.userService.Count(c.Request.Context(), countOptions)
if err != nil {
h.logger.Error("Failed to count users", zap.Error(err))
h.response.InternalError(c, "Failed to count users")
return
}
// 构建响应
userResponses := dto.FromEntities(users)
pagination := buildPagination(req.Page, req.PageSize, total)
h.response.Paginated(c, userResponses, pagination)
}
// Login 用户登录
func (h *UserHandler) Login(c *gin.Context) {
var req dto.LoginRequest
// 验证请求体
if err := h.validator.BindAndValidate(c, &req); err != nil {
return
}
// 用户登录
user, err := h.userService.Login(c.Request.Context(), &req)
if err != nil {
h.logger.Error("Login failed", zap.Error(err))
h.response.Unauthorized(c, "Invalid credentials")
return
}
// 生成JWT token
accessToken, err := h.jwtAuth.GenerateToken(user.ID, user.Username, user.Email)
if err != nil {
h.logger.Error("Failed to generate token", zap.Error(err))
h.response.InternalError(c, "Failed to generate access token")
return
}
// 构建登录响应
loginResponse := &dto.LoginResponse{
User: dto.FromEntity(user),
AccessToken: accessToken,
TokenType: "Bearer",
ExpiresIn: 86400, // 24小时从配置获取
}
h.response.Success(c, loginResponse, "Login successful")
}
// Logout 用户登出
func (h *UserHandler) Logout(c *gin.Context) {
// 简单实现客户端删除token即可
// 如果需要服务端黑名单,可以在这里实现
h.response.Success(c, nil, "Logout successful")
}
// GetProfile 获取当前用户信息
func (h *UserHandler) GetProfile(c *gin.Context) {
userID := h.getCurrentUserID(c)
if userID == "" {
h.response.Unauthorized(c, "User not authenticated")
return
}
// 获取用户信息
user, err := h.userService.GetByID(c.Request.Context(), userID)
if err != nil {
h.logger.Error("Failed to get user profile", zap.Error(err))
h.response.NotFound(c, "User not found")
return
}
// 返回响应
response := dto.FromEntity(user)
h.response.Success(c, response)
}
// UpdateProfile 更新当前用户信息
func (h *UserHandler) UpdateProfile(c *gin.Context) {
userID := h.getCurrentUserID(c)
if userID == "" {
h.response.Unauthorized(c, "User not authenticated")
return
}
var req dto.UpdateUserRequest
// 验证请求体
if err := h.validator.BindAndValidate(c, &req); err != nil {
return
}
// 更新用户
user, err := h.userService.Update(c.Request.Context(), userID, &req)
if err != nil {
h.logger.Error("Failed to update profile", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
// 返回响应
response := dto.FromEntity(user)
h.response.Success(c, response, "Profile updated successfully")
}
// ChangePassword 修改密码
func (h *UserHandler) ChangePassword(c *gin.Context) {
userID := h.getCurrentUserID(c)
if userID == "" {
h.response.Unauthorized(c, "User not authenticated")
return
}
var req dto.ChangePasswordRequest
// 验证请求体
if err := h.validator.BindAndValidate(c, &req); err != nil {
return
}
// 修改密码
if err := h.userService.ChangePassword(c.Request.Context(), userID, &req); err != nil {
h.logger.Error("Failed to change password", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
h.response.Success(c, nil, "Password changed successfully")
}
// Search 搜索用户
func (h *UserHandler) Search(c *gin.Context) {
var req dto.UserSearchRequest
// 验证查询参数
if err := h.validator.ValidateQuery(c, &req); err != nil {
return
}
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 10
}
// 构建查询选项
options := interfaces.ListOptions{
Page: req.Page,
PageSize: req.PageSize,
Search: req.Query,
}
// 搜索用户
users, err := h.userService.Search(c.Request.Context(), req.Query, options)
if err != nil {
h.logger.Error("Failed to search users", zap.Error(err))
h.response.InternalError(c, "Failed to search users")
return
}
// 获取搜索结果总数
countOptions := interfaces.CountOptions{
Search: req.Query,
}
total, err := h.userService.Count(c.Request.Context(), countOptions)
if err != nil {
h.logger.Error("Failed to count search results", zap.Error(err))
h.response.InternalError(c, "Failed to count search results")
return
}
// 构建响应
userResponses := dto.FromEntities(users)
pagination := buildPagination(req.Page, req.PageSize, total)
h.response.Paginated(c, userResponses, pagination)
}
// GetStats 获取用户统计
func (h *UserHandler) GetStats(c *gin.Context) {
stats, err := h.userService.GetStats(c.Request.Context())
if err != nil {
h.logger.Error("Failed to get user stats", zap.Error(err))
h.response.InternalError(c, "Failed to get user statistics")
return
}
h.response.Success(c, stats)
}
// 私有方法
// getCurrentUserID 获取当前用户ID
func (h *UserHandler) getCurrentUserID(c *gin.Context) string {
if userID, exists := c.Get("user_id"); exists {
if id, ok := userID.(string); ok {
return id
}
}
return ""
}
// parsePageSize 解析页面大小
func (h *UserHandler) parsePageSize(str string, defaultValue int) int {
if str == "" {
return defaultValue
}
if size, err := strconv.Atoi(str); err == nil && size > 0 && size <= 100 {
return size
}
return defaultValue
}
// parsePage 解析页码
func (h *UserHandler) parsePage(str string, defaultValue int) int {
if str == "" {
return defaultValue
}
if page, err := strconv.Atoi(str); err == nil && page > 0 {
return page
}
return defaultValue
}
// buildPagination 构建分页元数据
func buildPagination(page, pageSize int, total int64) interfaces.PaginationMeta {
totalPages := int(float64(total) / float64(pageSize))
if float64(total)/float64(pageSize) > float64(totalPages) {
totalPages++
}
if totalPages < 1 {
totalPages = 1
}
return interfaces.PaginationMeta{
Page: page,
PageSize: pageSize,
Total: total,
TotalPages: totalPages,
HasNext: page < totalPages,
HasPrev: page > 1,
}
}