Files
warehouse-management-BE/internal/services/auth_service.go
Tran Anh Tuan 6a4a96e0ca Base Project
2026-05-08 14:32:24 +07:00

129 lines
4.0 KiB
Go

package services
import (
"net/http"
"wm-backend/global"
"wm-backend/internal/models"
"wm-backend/internal/models/requests"
"wm-backend/internal/models/responses"
"wm-backend/internal/repositories"
"wm-backend/pkg/helper"
"wm-backend/response"
db "wm-backend/sqlc_gen"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5/pgtype"
"github.com/rs/zerolog/log"
)
// Register handles user registration.
// It validates the request body, checks for duplicate email,
// hashes the password, and creates the user in the database.
//
// @Summary Register a new user
// @Description Register with email, username and password
// @Tags auth
// @Accept json
// @Produce json
// @Param body body requests.BodyRegisterRequest true "Register request"
// @Success 201 {object} response.SuccessResponse{data=responses.BodyRegisterResponse}
// @Failure 400 {object} response.ErrorResponse
// @Failure 409 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /auth/register [post]
func Register(c *gin.Context) error {
// 1. Bind & validate request body
requestBody := requests.BodyRegisterRequest{}
if helper.IsShouldBindJSON(c, &requestBody) {
return nil
}
// 2. Check if user already exists by email
existingUser, err := repositories.GetUserByEmail(c.Request.Context(), global.Queries, requestBody.Email)
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError)
log.Error().Err(err).Msg("Error checking existing user")
return nil
}
if existingUser != nil {
response.ConflictError(c, http.StatusConflict, "Email already registered")
return nil
}
// 3. Hash the password
hashedPassword, err := helper.HashPassword(requestBody.Password)
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError)
log.Error().Err(err).Msg("Password hashing error")
return nil
}
// 4. Create user in database
userID, err := repositories.CreateUser(c.Request.Context(), global.Queries, db.CreateUserParams{
Username: requestBody.Username,
Email: requestBody.Email,
PasswordHash: hashedPassword,
FullName: pgtype.Text{String: requestBody.FullName, Valid: requestBody.FullName != ""},
CreatedBy: pgtype.Text{String: requestBody.Username, Valid: true},
})
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError)
log.Error().Err(err).Msg("Error creating user")
return nil
}
// 5. Return success response
response.Created(c, "User registered successfully", responses.BodyRegisterResponse{
ID: userID,
})
return nil
}
func Login(c *gin.Context) error {
loginRequestBody := requests.BodyLoginRequest{}
if helper.IsShouldBindJSON(c, &loginRequestBody) {
return nil
}
var user *models.User
var err error
if helper.IsEmail(loginRequestBody.Username) {
user, err = repositories.GetUserByEmail(c.Request.Context(), global.Queries, loginRequestBody.Username)
} else {
user, err = repositories.GetUserByUsername(c.Request.Context(), global.Queries, loginRequestBody.Username)
}
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError)
log.Error().Err(err).Msg("Error finding user")
return nil
}
if user == nil {
response.UnauthorizedError(c, http.StatusUnauthorized, "Invalid credentials")
return nil
}
// 2. Check if user is active
if !user.IsActive {
response.UnauthorizedError(c, http.StatusUnauthorized, "Account is disabled")
return nil
}
// 3. Compare password
if err := helper.ComparePassword(loginRequestBody.Password, user.PasswordHash); err != nil {
response.UnauthorizedError(c, http.StatusUnauthorized, "Invalid credentials")
return nil
}
// 4. Generate JWT token
token, err := helper.GenerateToken(user.ID)
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError)
log.Error().Err(err).Msg("Error generating token")
return nil
}
// 5. Return token
response.Ok(c, "Login successful", responses.BodyLoginResponse{
Token: token,
})
return nil
}