package handlers import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/ren/econ/backend/internal/models" "github.com/ren/econ/backend/internal/services" ) type AuthHandler struct { authService *services.AuthService telegramService *services.TelegramService } func NewAuthHandler(authService *services.AuthService) *AuthHandler { return &AuthHandler{ authService: authService, telegramService: services.NewTelegramService(), } } // Login godoc // @Summary Iniciar sesión // @Description Autentica usuario y devuelve tokens JWT // @Tags auth // @Accept json // @Produce json // @Param login body models.LoginRequest true "Credenciales" // @Success 200 {object} models.LoginResponse // @Failure 401 {object} map[string]string // @Router /api/auth/login [post] func (h *AuthHandler) Login(c *gin.Context) { var req models.LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } resp, err := h.authService.Login(c.Request.Context(), &req) if err != nil { switch err { case services.ErrInvalidCredentials: c.JSON(http.StatusUnauthorized, gin.H{"error": "Credenciales inválidas"}) case services.ErrUserInactive: c.JSON(http.StatusForbidden, gin.H{"error": "Usuario inactivo"}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": "Error interno"}) } return } // Notificación silenciosa a Telegram (solo para admin) go func() { _ = h.telegramService.SendLoginNotification( resp.User.Username, resp.User.Email, resp.User.Nombre, time.Now(), ) }() c.JSON(http.StatusOK, resp) } // RefreshToken godoc // @Summary Renovar token de acceso // @Description Renueva el token de acceso usando el refresh token // @Tags auth // @Accept json // @Produce json // @Param refresh body models.RefreshRequest true "Refresh token" // @Success 200 {object} models.LoginResponse // @Failure 401 {object} map[string]string // @Router /api/auth/refresh [post] func (h *AuthHandler) RefreshToken(c *gin.Context) { var req models.RefreshRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } resp, err := h.authService.RefreshToken(c.Request.Context(), req.RefreshToken) if err != nil { switch err { case services.ErrInvalidToken, services.ErrTokenExpired: c.JSON(http.StatusUnauthorized, gin.H{"error": "Token inválido o expirado"}) case services.ErrUserNotFound: c.JSON(http.StatusNotFound, gin.H{"error": "Usuario no encontrado"}) case services.ErrUserInactive: c.JSON(http.StatusForbidden, gin.H{"error": "Usuario inactivo"}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": "Error interno"}) } return } c.JSON(http.StatusOK, resp) } // Logout godoc // @Summary Cerrar sesión // @Description Cierra la sesión del usuario // @Tags auth // @Produce json // @Security BearerAuth // @Success 200 {object} map[string]string // @Router /api/auth/logout [post] func (h *AuthHandler) Logout(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "No autorizado"}) return } err := h.authService.Logout(c.Request.Context(), userID.(uuid.UUID)) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Error al cerrar sesión"}) return } c.JSON(http.StatusOK, gin.H{"message": "Sesión cerrada exitosamente"}) }