package controllers import ( "net/http" "strings" "whatsapp-backend/models/dto" http_error "whatsapp-backend/models/error" "whatsapp-backend/services" "whatsapp-backend/utils" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type AuthController interface { Register(ctx *gin.Context) Login(ctx *gin.Context) Logout(ctx *gin.Context) RefreshToken(ctx *gin.Context) Me(ctx *gin.Context) AssignRole(ctx *gin.Context) RegisterEnabled(ctx *gin.Context) } type authController struct { authService services.AuthService } func NewAuthController(authService services.AuthService) AuthController { return &authController{authService: authService} } // Register godoc // @Summary Register a new user // @Description Register a new user with the provided details // @Tags auth // @Accept json // @Produce json // @Param request body dto.RegisterRequest true "Register Request" // @Success 200 {object} dto.AuthResponse // @Failure 400 {object} dto.ErrorResponse // @Router /auth/register [post] func (c *authController) Register(ctx *gin.Context) { var req dto.RegisterRequest if err := ctx.ShouldBindJSON(&req); err != nil { utils.SendResponse[any, any](ctx, nil, nil, err) return } resp, err := c.authService.Register(req) if err != nil { utils.SendResponse[any, any](ctx, nil, nil, err) return } ctx.SetSameSite(http.SameSiteNoneMode) ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/", "", true, true) utils.SendResponse[dto.AuthResponse, any](ctx, nil, *resp, nil) } // Login godoc // @Summary Login a user // @Description Login a user with credentials // @Tags auth // @Accept json // @Produce json // @Param request body dto.LoginRequest true "Login Request" // @Success 200 {object} dto.AuthResponse // @Failure 400 {object} dto.ErrorResponse // @Router /auth/login [post] func (c *authController) Login(ctx *gin.Context) { var req dto.LoginRequest if err := ctx.ShouldBindJSON(&req); err != nil { utils.SendResponse[any, any](ctx, nil, nil, err) return } resp, err := c.authService.Login(req) if err != nil { utils.SendResponse[any, any](ctx, nil, nil, err) return } ctx.SetSameSite(http.SameSiteNoneMode) ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/", "", true, true) utils.SendResponse[dto.AuthResponse, any](ctx, nil, *resp, nil) } // Logout godoc // @Summary Logout a user // @Description Logout the current user // @Tags auth // @Security BearerAuth // @Success 200 // @Router /auth/logout [post] func (c *authController) Logout(ctx *gin.Context) { tokenString := "" authHeader := ctx.GetHeader("Authorization") if authHeader != "" { tokenString = strings.Replace(authHeader, "Bearer", "", 1) } else { cookie, err := ctx.Cookie("Authorization") if err == nil { tokenString = cookie } } refreshToken, _ := ctx.Cookie("RefreshToken") if tokenString != "" || refreshToken != "" { _ = c.authService.Logout(tokenString, refreshToken) } ctx.SetSameSite(http.SameSiteNoneMode) ctx.SetCookie("RefreshToken", "", -1, "/", "", true, true) utils.SendResponse[dto.LogoutResponse, any](ctx, nil, dto.LogoutResponse{ SuccessMsg: "Logout successful", }, nil) } // RefreshToken godoc // @Summary Refresh access token // @Description Refresh the access token using the refresh token cookie // @Tags auth // @Security BearerAuth // @Success 200 {object} dto.AuthResponse // @Failure 401 {object} dto.ErrorResponse // @Router /auth/refresh [post] func (c *authController) RefreshToken(ctx *gin.Context) { refreshToken, err := ctx.Cookie("RefreshToken") if err != nil || refreshToken == "" { utils.SendResponse[any, any](ctx, nil, nil, http_error.UNAUTHORIZED) return } newAccessToken, newRefreshToken, err := c.authService.RefreshToken(refreshToken) if err != nil { ctx.SetCookie("RefreshToken", "", -1, "/", "", true, true) utils.SendResponse[any, any](ctx, nil, nil, err) return } // Only set refresh token cookie if a new one was issued if newRefreshToken != "" { ctx.SetSameSite(http.SameSiteNoneMode) ctx.SetCookie("RefreshToken", newRefreshToken, 3600*24*7, "/", "", true, true) } utils.SendResponse[dto.AuthResponse, any](ctx, nil, dto.AuthResponse{ AccessToken: newAccessToken, }, nil) } // Me godoc // @Summary Get current user profile // @Description Get the profile of the currently logged-in user // @Tags auth // @Security BearerAuth // @Success 200 {object} dto.MeResponse // @Failure 401 {object} dto.ErrorResponse // @Router /auth/me [get] func (c *authController) Me(ctx *gin.Context) { userId, exists := ctx.Get("user_id") if !exists { utils.SendResponse[any, any](ctx, nil, nil, nil) return } resp, err := c.authService.GetMe(userId.(uuid.UUID)) if err != nil { utils.SendResponse[any, any](ctx, nil, nil, err) return } utils.SendResponse[dto.MeResponse, any](ctx, nil, *resp, nil) } // AssignRole godoc // @Summary Assign Role (SuperAdmin) // @Description Assign a role to a user // @Tags auth // @Security BearerAuth // @Accept json // @Produce json // @Param request body dto.AssignRoleRequest true "Assign Role Request" // @Success 200 // @Failure 400 {object} dto.ErrorResponse // @Router /auth/assign [post] func (c *authController) AssignRole(ctx *gin.Context) { var req dto.AssignRoleRequest if err := ctx.ShouldBindJSON(&req); err != nil { utils.SendResponse[any, any](ctx, nil, nil, err) return } if err := c.authService.AssignRole(req.UserID, req.Role); err != nil { utils.SendResponse[any, any](ctx, nil, nil, err) return } utils.SendResponse[any, any](ctx, nil, nil, nil) } // RegisterEnabled godoc // @Summary Check if registration is enabled // @Description Check if user registration is enabled // @Tags auth // @Security BearerAuth // @Success 200 {object} dto.RegisterEnabledResponse // @Router /auth/register_enabled [get] func (c *authController) RegisterEnabled(ctx *gin.Context) { utils.SendResponse[dto.RegisterEnabledResponse, any](ctx, nil, dto.RegisterEnabledResponse{ Register: c.authService.IsRegisterEnabled(), }, nil) }