whatsapp-backend-test / controllers /auth_controller.go
RyZ
fix: options database to key-based data structure
5c3fcbb
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)
}