Yimaru-BackEnd/internal/web_server/handlers/auth_handler.go
2025-04-10 14:59:31 +03:00

189 lines
6.6 KiB
Go

package handlers
import (
"errors"
"log/slog"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
"github.com/gofiber/fiber/v2"
)
type loginCustomerReq struct {
Email string `json:"email" example:"john.doe@example.com"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
Password string `json:"password" example:"password123"`
}
type loginCustomerRes struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
Role string `json:"role"`
}
// LoginCustomer godoc
// @Summary Login customer
// @Description Login customer
// @Tags auth
// @Accept json
// @Produce json
// @Param login body loginCustomerReq true "Login customer"
// @Success 200 {object} loginCustomerRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /auth/login [post]
func LoginCustomer(
logger *slog.Logger, authSvc *authentication.Service,
validator *customvalidator.CustomValidator, JwtConfig jwtutil.JwtConfig) fiber.Handler {
return func(c *fiber.Ctx) error {
var req loginCustomerReq
if err := c.BodyParser(&req); err != nil {
logger.Error("Login failed", "error", err)
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
}
valErrs, ok := validator.Validate(c, req)
if !ok {
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
return nil
}
successRes, err := authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password)
if err != nil {
logger.Info("Login failed", "error", err)
if errors.Is(err, authentication.ErrInvalidPassword) {
response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid password or not registered", nil, nil)
return nil
}
if errors.Is(err, authentication.ErrUserNotFound) {
response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid password or not registered", nil, nil)
return nil
}
logger.Error("Login failed", "error", err)
response.WriteJSON(c, fiber.StatusInternalServerError, "Internal server error", nil, nil)
return nil
}
accessToken, err := jwtutil.CreateJwt(successRes.UserId, successRes.Role, successRes.BranchId, JwtConfig.JwtAccessKey, JwtConfig.JwtAccessExpiry)
res := loginCustomerRes{
AccessToken: accessToken,
RefreshToken: successRes.RfToken,
Role: string(successRes.Role),
}
return response.WriteJSON(c, fiber.StatusOK, "Login successful", res, nil)
}
}
type refreshToken struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
// RefreshToken godoc
// @Summary Refresh token
// @Description Refresh token
// @Tags auth
// @Accept json
// @Produce json
// @Param refresh body refreshToken true "tokens"
// @Success 200 {object} loginCustomerRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /auth/refresh [post]
func RefreshToken(logger *slog.Logger, authSvc *authentication.Service,
validator *customvalidator.CustomValidator, JwtConfig jwtutil.JwtConfig) fiber.Handler {
return func(c *fiber.Ctx) error {
var req refreshToken
if err := c.BodyParser(&req); err != nil {
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
}
valErrs, ok := validator.Validate(c, req)
if !ok {
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
return nil
}
userId := c.Locals("user_id").(int64)
role := c.Locals("role").(string)
branchId := c.Locals("branch_id").(int64)
err := authSvc.RefreshToken(c.Context(), req.RefreshToken)
if err != nil {
logger.Info("Refresh token failed", "error", err)
if errors.Is(err, authentication.ErrExpiredToken) {
response.WriteJSON(c, fiber.StatusUnauthorized, "The refresh token has expired", nil, nil)
return nil
}
if errors.Is(err, authentication.ErrRefreshTokenNotFound) {
response.WriteJSON(c, fiber.StatusUnauthorized, "Refresh token not found", nil, nil)
return nil
}
logger.Error("Refresh token failed", "error", err)
response.WriteJSON(c, fiber.StatusInternalServerError, "Internal server error", nil, nil)
return nil
}
accessToken, err := jwtutil.CreateJwt(userId, domain.Role(role), branchId, JwtConfig.JwtAccessKey, JwtConfig.JwtAccessExpiry)
if err != nil {
logger.Error("Create jwt failed", "error", err)
response.WriteJSON(c, fiber.StatusInternalServerError, "Internal server error", nil, nil)
return nil
}
res := loginCustomerRes{
AccessToken: accessToken,
RefreshToken: req.RefreshToken,
}
return response.WriteJSON(c, fiber.StatusOK, "refresh successful", res, nil)
}
}
type logoutReq struct {
RefreshToken string `json:"refresh_token"`
}
// LogOutCustomer godoc
// @Summary Logout customer
// @Description Logout customer
// @Tags auth
// @Accept json
// @Produce json
// @Param logout body logoutReq true "Logout customer"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /auth/logout [post]
func LogOutCustomer(
logger *slog.Logger, authSvc *authentication.Service,
validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
var req logoutReq
if err := c.BodyParser(&req); err != nil {
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
}
valErrs, ok := validator.Validate(c, req)
if !ok {
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
return nil
}
err := authSvc.Logout(c.Context(), req.RefreshToken)
if err != nil {
logger.Info("Logout failed", "error", err)
if errors.Is(err, authentication.ErrExpiredToken) {
response.WriteJSON(c, fiber.StatusUnauthorized, "The refresh token has expired", nil, nil)
return nil
}
if errors.Is(err, authentication.ErrRefreshTokenNotFound) {
response.WriteJSON(c, fiber.StatusUnauthorized, "Refresh token not found", nil, nil)
return nil
}
logger.Error("Logout failed", "error", err)
response.WriteJSON(c, fiber.StatusInternalServerError, "Internal server error", nil, nil)
return nil
}
return response.WriteJSON(c, fiber.StatusOK, "Logout successful", nil, nil)
}
}