package handlers import ( "net/http" "github.com/gin-gonic/gin" "github.com/mchus/quoteforge/internal/middleware" "github.com/mchus/quoteforge/internal/repository" "github.com/mchus/quoteforge/internal/services" ) type AuthHandler struct { authService *services.AuthService userRepo *repository.UserRepository } func NewAuthHandler(authService *services.AuthService, userRepo *repository.UserRepository) *AuthHandler { return &AuthHandler{ authService: authService, userRepo: userRepo, } } type LoginRequest struct { Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` } type LoginResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresAt int64 `json:"expires_at"` User UserResponse `json:"user"` } type UserResponse struct { ID uint `json:"id"` Username string `json:"username"` Email string `json:"email"` Role string `json:"role"` } func (h *AuthHandler) Login(c *gin.Context) { var req LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } tokens, user, err := h.authService.Login(req.Username, req.Password) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, LoginResponse{ AccessToken: tokens.AccessToken, RefreshToken: tokens.RefreshToken, ExpiresAt: tokens.ExpiresAt, User: UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, Role: string(user.Role), }, }) } type RefreshRequest struct { RefreshToken string `json:"refresh_token" binding:"required"` } func (h *AuthHandler) Refresh(c *gin.Context) { var req RefreshRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } tokens, err := h.authService.RefreshTokens(req.RefreshToken) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, tokens) } func (h *AuthHandler) Me(c *gin.Context) { claims := middleware.GetClaims(c) if claims == nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "not authenticated"}) return } user, err := h.userRepo.GetByID(claims.UserID) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "user not found"}) return } c.JSON(http.StatusOK, UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, Role: string(user.Role), }) } func (h *AuthHandler) Logout(c *gin.Context) { // JWT is stateless, logout is handled on client by discarding tokens c.JSON(http.StatusOK, gin.H{"message": "logged out"}) }