[feature/backend] implement /users handler + switch to username + add display name + user management cli
This commit is contained in:
parent
1d712d4e6c
commit
86ab334bc9
38 changed files with 1851 additions and 506 deletions
227
backend/internal/handler/user.go
Normal file
227
backend/internal/handler/user.go
Normal file
|
@ -0,0 +1,227 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
"tss-rocks-be/internal/types"
|
||||
)
|
||||
|
||||
type UpdateCurrentUserRequest struct {
|
||||
Email string `json:"email,omitempty" binding:"omitempty,email"`
|
||||
CurrentPassword string `json:"current_password,omitempty"`
|
||||
NewPassword string `json:"new_password,omitempty" binding:"omitempty,min=8"`
|
||||
DisplayName string `json:"display_name,omitempty" binding:"omitempty,max=64"`
|
||||
}
|
||||
|
||||
type CreateUserRequest struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Password string `json:"password" binding:"required,min=8"`
|
||||
Role string `json:"role" binding:"required,oneof=admin editor"`
|
||||
DisplayName string `json:"display_name,omitempty" binding:"omitempty,max=64"`
|
||||
}
|
||||
|
||||
type UpdateUserRequest struct {
|
||||
Email string `json:"email,omitempty" binding:"omitempty,email"`
|
||||
Password string `json:"password,omitempty" binding:"omitempty,min=8"`
|
||||
Role string `json:"role,omitempty" binding:"omitempty,oneof=admin editor"`
|
||||
Status string `json:"status,omitempty" binding:"omitempty,oneof=active inactive"`
|
||||
DisplayName string `json:"display_name,omitempty" binding:"omitempty,max=64"`
|
||||
}
|
||||
|
||||
// ListUsers returns a list of users
|
||||
func (h *Handler) ListUsers(c *gin.Context) {
|
||||
// Parse query parameters
|
||||
params := &types.ListUsersParams{
|
||||
Page: 1,
|
||||
PerPage: 10,
|
||||
}
|
||||
|
||||
if page := c.Query("page"); page != "" {
|
||||
if p, err := strconv.Atoi(page); err == nil && p > 0 {
|
||||
params.Page = p
|
||||
}
|
||||
}
|
||||
|
||||
if perPage := c.Query("per_page"); perPage != "" {
|
||||
if pp, err := strconv.Atoi(perPage); err == nil && pp > 0 {
|
||||
params.PerPage = pp
|
||||
}
|
||||
}
|
||||
|
||||
params.Sort = c.Query("sort")
|
||||
params.Role = c.Query("role")
|
||||
params.Status = c.Query("status")
|
||||
params.Email = c.Query("email")
|
||||
|
||||
// Get users
|
||||
users, err := h.service.ListUsers(c.Request.Context(), params)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to list users")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list users"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": users,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateUser creates a new user
|
||||
func (h *Handler) CreateUser(c *gin.Context) {
|
||||
var req CreateUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.service.CreateUser(c.Request.Context(), req.Email, req.Email, req.Password, req.Role)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to create user")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{
|
||||
"data": user,
|
||||
})
|
||||
}
|
||||
|
||||
// GetUser returns user details
|
||||
func (h *Handler) GetUser(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.service.GetUser(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get user")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": user,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateUser updates user information
|
||||
func (h *Handler) UpdateUser(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var req UpdateUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.service.UpdateUser(c.Request.Context(), id, &types.UpdateUserInput{
|
||||
Email: req.Email,
|
||||
Password: req.Password,
|
||||
Role: req.Role,
|
||||
Status: req.Status,
|
||||
DisplayName: req.DisplayName,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to update user")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": user,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteUser deletes a user
|
||||
func (h *Handler) DeleteUser(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.DeleteUser(c.Request.Context(), id); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to delete user")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// GetCurrentUser returns the current user's information
|
||||
func (h *Handler) GetCurrentUser(c *gin.Context) {
|
||||
// 从上下文中获取用户ID(由认证中间件设置)
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
user, err := h.service.GetUser(c.Request.Context(), userID.(int))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get user")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user information"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": user,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateCurrentUser updates the current user's information
|
||||
func (h *Handler) UpdateCurrentUser(c *gin.Context) {
|
||||
// 从上下文中获取用户ID(由认证中间件设置)
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
||||
return
|
||||
}
|
||||
|
||||
var req UpdateCurrentUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// 如果要更新密码,需要验证当前密码
|
||||
if req.NewPassword != "" {
|
||||
if req.CurrentPassword == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Current password is required to update password"})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证当前密码
|
||||
if err := h.service.VerifyPassword(c.Request.Context(), userID.(int), 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{
|
||||
Email: req.Email,
|
||||
Password: req.NewPassword,
|
||||
DisplayName: req.DisplayName,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to update user")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user information"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": user,
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue