Initial commit: Plataforma de Economía
Features: - React 18 + TypeScript frontend with Vite - Go + Gin backend API - PostgreSQL database - JWT authentication with refresh tokens - User management (admin panel) - Docker containerization - Progress tracking system - 4 economic modules structure Fixed: - Login with username or email - User creation without required email - Database nullable timestamps - API response field naming
This commit is contained in:
230
backend/internal/handlers/users.go
Normal file
230
backend/internal/handlers/users.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/ren/econ/backend/internal/models"
|
||||
"github.com/ren/econ/backend/internal/repository"
|
||||
"github.com/ren/econ/backend/internal/services"
|
||||
)
|
||||
|
||||
type UsersHandler struct {
|
||||
userRepo *repository.UserRepository
|
||||
progresoRepo *repository.ProgresoRepository
|
||||
authService *services.AuthService
|
||||
}
|
||||
|
||||
func NewUsersHandler(userRepo *repository.UserRepository, progresoRepo *repository.ProgresoRepository, authService *services.AuthService) *UsersHandler {
|
||||
return &UsersHandler{
|
||||
userRepo: userRepo,
|
||||
progresoRepo: progresoRepo,
|
||||
authService: authService,
|
||||
}
|
||||
}
|
||||
|
||||
// ListUsers godoc
|
||||
// @Summary Listar usuarios
|
||||
// @Description Lista todos los usuarios (solo admin)
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {array} models.Usuario
|
||||
// @Router /api/admin/usuarios [get]
|
||||
func (h *UsersHandler) ListUsers(c *gin.Context) {
|
||||
users, err := h.userRepo.List(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error al listar usuarios"})
|
||||
return
|
||||
}
|
||||
|
||||
if users == nil {
|
||||
users = []models.Usuario{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, users)
|
||||
}
|
||||
|
||||
// CreateUser godoc
|
||||
// @Summary Crear usuario
|
||||
// @Description Crea un nuevo usuario (solo admin)
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param usuario body models.UsuarioCreate true "Usuario a crear"
|
||||
// @Security BearerAuth
|
||||
// @Success 201 {object} models.Usuario
|
||||
// @Router /api/admin/usuarios [post]
|
||||
func (h *UsersHandler) CreateUser(c *gin.Context) {
|
||||
var req models.UsuarioCreate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Hash password if provided
|
||||
passwordHash := req.Password
|
||||
if passwordHash != "" {
|
||||
hash, err := h.authService.HashPassword(passwordHash)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error al hashear password"})
|
||||
return
|
||||
}
|
||||
passwordHash = hash
|
||||
}
|
||||
|
||||
user := &models.Usuario{
|
||||
Username: req.Username,
|
||||
Email: req.Email,
|
||||
PasswordHash: passwordHash,
|
||||
Nombre: req.Nombre,
|
||||
Rol: req.Rol,
|
||||
}
|
||||
|
||||
// Si no se proporciona email, generar uno automáticamente basado en el username
|
||||
if user.Email == "" {
|
||||
user.Email = req.Username + "@econ.local"
|
||||
}
|
||||
|
||||
if user.Rol == "" {
|
||||
user.Rol = "estudiante"
|
||||
}
|
||||
|
||||
err := h.userRepo.Create(c.Request.Context(), user)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error al crear usuario: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, user)
|
||||
}
|
||||
|
||||
// GetUser godoc
|
||||
// @Summary Obtener usuario
|
||||
// @Description Obtiene un usuario por ID (solo admin)
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "ID del usuario"
|
||||
// @Success 200 {object} models.Usuario
|
||||
// @Router /api/admin/usuarios/{id} [get]
|
||||
func (h *UsersHandler) GetUser(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ID inválido"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userRepo.GetByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Usuario no encontrado"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, user)
|
||||
}
|
||||
|
||||
// UpdateUser godoc
|
||||
// @Summary Actualizar usuario
|
||||
// @Description Actualiza un usuario (solo admin)
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID del usuario"
|
||||
// @Param usuario body models.UsuarioUpdate true "Datos a actualizar"
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} models.Usuario
|
||||
// @Router /api/admin/usuarios/{id} [put]
|
||||
func (h *UsersHandler) UpdateUser(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ID inválido"})
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UsuarioUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userRepo.GetByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Usuario no encontrado"})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Email != "" {
|
||||
user.Email = req.Email
|
||||
}
|
||||
if req.Nombre != "" {
|
||||
user.Nombre = req.Nombre
|
||||
}
|
||||
if req.Activo != nil {
|
||||
user.Activo = *req.Activo
|
||||
}
|
||||
|
||||
err = h.userRepo.Update(c.Request.Context(), user)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error al actualizar usuario"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, user)
|
||||
}
|
||||
|
||||
// DeleteUser godoc
|
||||
// @Summary Eliminar usuario
|
||||
// @Description Desactiva un usuario (solo admin)
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "ID del usuario"
|
||||
// @Success 200 {object} map[string]string
|
||||
// @Router /api/admin/usuarios/{id} [delete]
|
||||
func (h *UsersHandler) DeleteUser(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ID inválido"})
|
||||
return
|
||||
}
|
||||
|
||||
err = h.userRepo.Delete(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error al eliminar usuario"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Usuario desactivado exitosamente"})
|
||||
}
|
||||
|
||||
// GetUserProgreso godoc
|
||||
// @Summary Ver progreso de usuario
|
||||
// @Description Obtiene el progreso de un usuario (solo admin)
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "ID del usuario"
|
||||
// @Success 200 {array} models.Progreso
|
||||
// @Router /api/admin/usuarios/{id}/progreso [get]
|
||||
func (h *UsersHandler) GetUserProgreso(c *gin.Context) {
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ID inválido"})
|
||||
return
|
||||
}
|
||||
|
||||
progresos, err := h.progresoRepo.GetByUsuarioID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error al obtener progreso"})
|
||||
return
|
||||
}
|
||||
|
||||
if progresos == nil {
|
||||
progresos = []models.Progreso{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, progresos)
|
||||
}
|
||||
Reference in New Issue
Block a user