Files
2025-09-13 06:48:55 +03:00

454 lines
11 KiB
Go

package handlers
import (
"fmt"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"customer-support-system/internal/auth"
"customer-support-system/internal/database"
"customer-support-system/internal/models"
"customer-support-system/pkg/logger"
)
// UserHandler handles user-related HTTP requests
type UserHandler struct {
authService *auth.AuthService
}
// NewUserHandler creates a new user handler
func NewUserHandler() *UserHandler {
return &UserHandler{
authService: auth.NewAuthService(database.GetDB()),
}
}
// Register handles user registration
func (h *UserHandler) Register(c *gin.Context) {
var req models.CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.WithError(err).Error("Failed to parse register request")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid request body",
})
return
}
// Validate request
if err := validateRegisterRequest(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": err.Error(),
})
return
}
// Create user
user, err := h.authService.Register(&req)
if err != nil {
logger.WithError(err).Error("Failed to register user")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to register user",
})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"message": "User registered successfully",
"data": gin.H{
"user": user,
},
})
}
// Login handles user login
func (h *UserHandler) Login(c *gin.Context) {
var req models.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.WithError(err).Error("Failed to parse login request")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid request body",
})
return
}
// Validate request
if err := validateLoginRequest(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": err.Error(),
})
return
}
// Get client IP
clientIP := c.ClientIP()
// Authenticate user
response, err := h.authService.Login(req.Username, req.Password, clientIP)
if err != nil {
logger.WithError(err).Error("Failed to login user")
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "Invalid username or password",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "User logged in successfully",
"data": gin.H{
"user": response.User,
"token": response.Token,
},
})
}
// GetProfile handles getting user profile
func (h *UserHandler) GetProfile(c *gin.Context) {
// Get user ID from context
userID, exists := c.Get("userID")
if !exists {
logger.Error("Failed to get user ID from context")
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "Unauthorized",
})
return
}
// Get user profile
user, err := h.authService.GetUserByID(userID.(uint))
if err != nil {
logger.WithError(err).Error("Failed to get user profile")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to get user profile",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"user": user.ToSafeUser(),
},
})
}
// UpdateProfile handles updating user profile
func (h *UserHandler) UpdateProfile(c *gin.Context) {
// Get user ID from context
userID, exists := c.Get("userID")
if !exists {
logger.Error("Failed to get user ID from context")
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "Unauthorized",
})
return
}
var req models.UpdateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.WithError(err).Error("Failed to parse update profile request")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid request body",
})
return
}
// Update user profile
user, err := h.authService.UpdateUser(userID.(uint), &req)
if err != nil {
logger.WithError(err).Error("Failed to update user profile")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to update user profile",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "User profile updated successfully",
"data": gin.H{
"user": user,
},
})
}
// ChangePassword handles changing user password
func (h *UserHandler) ChangePassword(c *gin.Context) {
// Get user ID from context
userID, exists := c.Get("userID")
if !exists {
logger.Error("Failed to get user ID from context")
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "Unauthorized",
})
return
}
var req models.ChangePasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.WithError(err).Error("Failed to parse change password request")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid request body",
})
return
}
// Validate request
if err := validateChangePasswordRequest(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": err.Error(),
})
return
}
// Change password
err := h.authService.ChangePassword(userID.(uint), &req)
if err != nil {
logger.WithError(err).Error("Failed to change password")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to change password",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Password changed successfully",
})
}
// validateRegisterRequest validates the register request
func validateRegisterRequest(req *models.CreateUserRequest) error {
if req.Username == "" {
return fmt.Errorf("username is required")
}
if req.Password == "" {
return fmt.Errorf("password is required")
}
if req.Email == "" {
return fmt.Errorf("email is required")
}
return nil
}
// validateLoginRequest validates the login request
func validateLoginRequest(req *models.LoginRequest) error {
if req.Username == "" {
return fmt.Errorf("username is required")
}
if req.Password == "" {
return fmt.Errorf("password is required")
}
return nil
}
// validateChangePasswordRequest validates the change password request
func validateChangePasswordRequest(req *models.ChangePasswordRequest) error {
if req.CurrentPassword == "" {
return fmt.Errorf("current password is required")
}
if req.NewPassword == "" {
return fmt.Errorf("new password is required")
}
return nil
}
// AdminGetUsers handles getting all users (admin only)
func (h *UserHandler) AdminGetUsers(c *gin.Context) {
// Parse query parameters
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 10
}
// Get users
var users []models.User
var total int64
db := database.GetDB()
// Get total count
if err := db.Model(&models.User{}).Count(&total).Error; err != nil {
logger.WithError(err).Error("Failed to count users")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to count users",
})
return
}
// Get paginated results
offset := (page - 1) * pageSize
if err := db.Offset(offset).Limit(pageSize).Find(&users).Error; err != nil {
logger.WithError(err).Error("Failed to get users")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to get users",
})
return
}
// Convert to safe users
safeUsers := make([]models.SafeUser, len(users))
for i, user := range users {
safeUsers[i] = user.ToSafeUser()
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"users": safeUsers,
"total": total,
"page": page,
"pageSize": pageSize,
},
})
}
// AdminGetUser handles getting a user by ID (admin only)
func (h *UserHandler) AdminGetUser(c *gin.Context) {
// Get target user ID from URL params
targetUserID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
logger.WithError(err).Error("Failed to parse user ID")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid user ID",
})
return
}
// Get user
user, err := h.authService.GetUserByID(uint(targetUserID))
if err != nil {
logger.WithError(err).Error("Failed to get user")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to get user",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"user": user.ToSafeUser(),
},
})
}
// AdminUpdateUser handles updating a user (admin only)
func (h *UserHandler) AdminUpdateUser(c *gin.Context) {
// Get target user ID from URL params
targetUserID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
logger.WithError(err).Error("Failed to parse user ID")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid user ID",
})
return
}
var req models.UpdateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.WithError(err).Error("Failed to parse update user request")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid request body",
})
return
}
// Update user
updatedUser, err := h.authService.UpdateUser(uint(targetUserID), &req)
if err != nil {
logger.WithError(err).Error("Failed to update user")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to update user",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "User updated successfully",
"data": gin.H{
"user": updatedUser,
},
})
}
// AdminDeleteUser handles deleting a user (admin only)
func (h *UserHandler) AdminDeleteUser(c *gin.Context) {
// Get target user ID from URL params
targetUserID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
logger.WithError(err).Error("Failed to parse user ID")
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Invalid user ID",
})
return
}
// Get current user ID from context
currentUserID, exists := c.Get("userID")
if !exists {
logger.Error("Failed to get current user ID from context")
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "Unauthorized",
})
return
}
// Prevent self-deletion
if currentUserID.(uint) == uint(targetUserID) {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Cannot delete your own account",
})
return
}
// Delete user
db := database.GetDB()
if err := db.Delete(&models.User{}, uint(targetUserID)).Error; err != nil {
logger.WithError(err).Error("Failed to delete user")
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Failed to delete user",
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "User deleted successfully",
})
}