203 lines
5.9 KiB
Go
203 lines
5.9 KiB
Go
package auth
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"photum-backend/internal/profissionais"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Handler struct {
|
|
service *Service
|
|
}
|
|
|
|
func NewHandler(service *Service) *Handler {
|
|
return &Handler{service: service}
|
|
}
|
|
|
|
type registerRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Senha string `json:"senha" binding:"required,min=6"`
|
|
Role string `json:"role" binding:"required,oneof=profissional empresa"`
|
|
ProfissionalData *profissionais.CreateProfissionalInput `json:"profissional_data"`
|
|
}
|
|
|
|
// Register godoc
|
|
// @Summary Register a new user
|
|
// @Description Register a new user with optional professional profile
|
|
// @Tags auth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body registerRequest true "Register Request"
|
|
// @Success 201 {object} map[string]string
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /auth/register [post]
|
|
func (h *Handler) Register(c *gin.Context) {
|
|
var req registerRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
if req.Role == "profissional" && req.ProfissionalData == nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "profissional_data is required for role 'profissional'"})
|
|
return
|
|
}
|
|
|
|
_, err := h.service.Register(c.Request.Context(), req.Email, req.Senha, req.Role, req.ProfissionalData)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, gin.H{"message": "user created"})
|
|
}
|
|
|
|
type loginRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Senha string `json:"senha" binding:"required"`
|
|
}
|
|
|
|
type loginResponse struct {
|
|
AccessToken string `json:"access_token"`
|
|
ExpiresAt string `json:"expires_at"`
|
|
User userResponse `json:"user"`
|
|
Profissional interface{} `json:"profissional,omitempty"`
|
|
}
|
|
|
|
type userResponse struct {
|
|
ID string `json:"id"`
|
|
Email string `json:"email"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
// Login godoc
|
|
// @Summary Login
|
|
// @Description Login with email and password
|
|
// @Tags auth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body loginRequest true "Login Request"
|
|
// @Success 200 {object} loginResponse
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /auth/login [post]
|
|
func (h *Handler) Login(c *gin.Context) {
|
|
var req loginRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
tokenPair, user, profData, err := h.service.Login(c.Request.Context(), req.Email, req.Senha)
|
|
if err != nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
http.SetCookie(c.Writer, &http.Cookie{
|
|
Name: "refresh_token",
|
|
Value: tokenPair.RefreshToken,
|
|
Path: "/auth/refresh",
|
|
HttpOnly: true,
|
|
Secure: false,
|
|
SameSite: http.SameSiteStrictMode,
|
|
MaxAge: 30 * 24 * 60 * 60,
|
|
})
|
|
|
|
resp := loginResponse{
|
|
AccessToken: tokenPair.AccessToken,
|
|
ExpiresAt: "2025-...",
|
|
User: userResponse{
|
|
ID: uuid.UUID(user.ID.Bytes).String(),
|
|
Email: user.Email,
|
|
Role: user.Role,
|
|
},
|
|
}
|
|
|
|
if profData != nil {
|
|
resp.Profissional = map[string]interface{}{
|
|
"id": uuid.UUID(profData.ID.Bytes).String(),
|
|
"nome": profData.Nome,
|
|
"funcao_profissional_id": uuid.UUID(profData.FuncaoProfissionalID.Bytes).String(),
|
|
"funcao_profissional": profData.FuncaoNome.String,
|
|
"equipamentos": profData.Equipamentos.String,
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|
|
|
|
// Refresh and Logout handlers should be kept or restored if they were lost.
|
|
// I will assume they are needed and add them back in a subsequent edit if missing,
|
|
// or include them here if I can fit them.
|
|
// The previous content had them. I'll add them to be safe.
|
|
|
|
// Refresh godoc
|
|
// @Summary Refresh access token
|
|
// @Description Get a new access token using a valid refresh token
|
|
// @Tags auth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param refresh_token body string false "Refresh Token"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Failure 401 {object} map[string]string
|
|
// @Router /auth/refresh [post]
|
|
func (h *Handler) Refresh(c *gin.Context) {
|
|
refreshToken, err := c.Cookie("refresh_token")
|
|
if err != nil {
|
|
var req struct {
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err == nil {
|
|
refreshToken = req.RefreshToken
|
|
}
|
|
}
|
|
|
|
if refreshToken == "" {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "refresh token required"})
|
|
return
|
|
}
|
|
|
|
accessToken, accessExp, err := h.service.Refresh(c.Request.Context(), refreshToken)
|
|
if err != nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid refresh token"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"access_token": accessToken,
|
|
"expires_at": accessExp,
|
|
})
|
|
}
|
|
|
|
// Logout godoc
|
|
// @Summary Logout user
|
|
// @Description Revoke refresh token and clear cookie
|
|
// @Tags auth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param refresh_token body string false "Refresh Token"
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /auth/logout [post]
|
|
func (h *Handler) Logout(c *gin.Context) {
|
|
refreshToken, err := c.Cookie("refresh_token")
|
|
if err != nil {
|
|
var req struct {
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err == nil {
|
|
refreshToken = req.RefreshToken
|
|
}
|
|
}
|
|
|
|
if refreshToken != "" {
|
|
_ = h.service.Logout(c.Request.Context(), refreshToken)
|
|
}
|
|
|
|
c.SetCookie("refresh_token", "", -1, "/", "", false, true)
|
|
c.JSON(http.StatusOK, gin.H{"message": "logged out"})
|
|
}
|