package handler import ( "apskel-pos-be/internal/util" "net/http" "strings" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/contract" "apskel-pos-be/internal/logger" "apskel-pos-be/internal/service" "apskel-pos-be/internal/transformer" "github.com/gin-gonic/gin" ) type AuthHandler struct { authService service.AuthService } func NewAuthHandler(authService service.AuthService) *AuthHandler { return &AuthHandler{ authService: authService, } } func (h *AuthHandler) Login(c *gin.Context) { var req contract.LoginRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Login -> request binding failed") h.sendValidationErrorResponse(c, "Invalid request body", constants.MissingFieldErrorCode) return } if strings.TrimSpace(req.Email) == "" { logger.FromContext(c.Request.Context()).Error("AuthHandler::Login -> email is required") h.sendValidationErrorResponse(c, "Email is required", constants.MissingFieldErrorCode) return } if strings.TrimSpace(req.Password) == "" { logger.FromContext(c.Request.Context()).Error("AuthHandler::Login -> password is required") h.sendValidationErrorResponse(c, "Password is required", constants.MissingFieldErrorCode) return } loginResponse, err := h.authService.Login(c.Request.Context(), &req) if err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Login -> Failed to login") h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized) return } logger.FromContext(c.Request.Context()).Infof("AuthHandler::Login -> Successfully logged in user = %s", loginResponse.User.Email) util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(loginResponse), "AuthHandler::Login") } func (h *AuthHandler) Logout(c *gin.Context) { token := h.extractTokenFromHeader(c) if token == "" { logger.FromContext(c.Request.Context()).Error("AuthHandler::Logout -> token is required") h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized) return } err := h.authService.Logout(c.Request.Context(), token) if err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Logout -> Failed to logout") h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized) return } logger.FromContext(c.Request.Context()).Info("AuthHandler::Logout -> Successfully logged out") c.JSON(http.StatusOK, transformer.CreateSuccessResponse("Successfully logged out", nil)) } func (h *AuthHandler) RefreshToken(c *gin.Context) { token := h.extractTokenFromHeader(c) if token == "" { logger.FromContext(c.Request.Context()).Error("AuthHandler::RefreshToken -> token is required") h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized) return } loginResponse, err := h.authService.RefreshToken(c.Request.Context(), token) if err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::RefreshToken -> Failed to refresh token") h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized) return } logger.FromContext(c.Request.Context()).Infof("AuthHandler::RefreshToken -> Successfully refreshed token for user = %s", loginResponse.User.Email) c.JSON(http.StatusOK, loginResponse) } func (h *AuthHandler) ValidateToken(c *gin.Context) { token := h.extractTokenFromHeader(c) if token == "" { logger.FromContext(c.Request.Context()).Error("AuthHandler::ValidateToken -> token is required") h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized) return } userResponse, err := h.authService.ValidateToken(token) if err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::ValidateToken -> Failed to validate token") h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized) return } logger.FromContext(c.Request.Context()).Infof("AuthHandler::ValidateToken -> Successfully validated token for user = %s", userResponse.Email) c.JSON(http.StatusOK, userResponse) } func (h *AuthHandler) GetProfile(c *gin.Context) { token := h.extractTokenFromHeader(c) if token == "" { logger.FromContext(c.Request.Context()).Error("AuthHandler::GetProfile -> token is required") h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized) return } userResponse, err := h.authService.ValidateToken(token) if err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::GetProfile -> Failed to get profile") h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized) return } logger.FromContext(c.Request.Context()).Infof("AuthHandler::GetProfile -> Successfully retrieved profile for user = %s", userResponse.Email) c.JSON(http.StatusOK, userResponse) } // Helper methods func (h *AuthHandler) extractTokenFromHeader(c *gin.Context) string { authHeader := c.GetHeader("Authorization") if authHeader == "" { return "" } // Expected format: "Bearer " parts := strings.Split(authHeader, " ") if len(parts) != 2 || parts[0] != "Bearer" { return "" } return parts[1] } func (h *AuthHandler) sendErrorResponse(c *gin.Context, message string, statusCode int) { errorResponse := &contract.ErrorResponse{ Error: "error", Message: message, Code: statusCode, } c.JSON(statusCode, errorResponse) } func (h *AuthHandler) sendValidationErrorResponse(c *gin.Context, message string, errorCode string) { errorResponse := &contract.ErrorResponse{ Error: "validation_error", Message: message, Code: http.StatusBadRequest, Details: map[string]interface{}{ "error_code": errorCode, "entity": constants.AuthHandlerEntity, }, } c.JSON(http.StatusBadRequest, errorResponse) }