2025-11-17 12:17:44 +07:00

172 lines
4.3 KiB
Go

package services
import (
"errors"
"lost-and-found/internal/config"
"lost-and-found/internal/models"
"lost-and-found/internal/repositories"
"lost-and-found/internal/utils"
"gorm.io/gorm"
)
type AuthService struct {
userRepo *repositories.UserRepository
roleRepo *repositories.RoleRepository
auditLogRepo *repositories.AuditLogRepository
}
func NewAuthService(db *gorm.DB) *AuthService {
return &AuthService{
userRepo: repositories.NewUserRepository(db),
roleRepo: repositories.NewRoleRepository(db),
auditLogRepo: repositories.NewAuditLogRepository(db),
}
}
// RegisterRequest represents registration data
type RegisterRequest struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=6"`
NRP string `json:"nrp"`
Phone string `json:"phone"`
}
// LoginRequest represents login data
type LoginRequest struct {
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required"`
}
// AuthResponse represents authentication response
type AuthResponse struct {
Token string `json:"token"`
User models.UserResponse `json:"user"`
}
// Register registers a new user
func (s *AuthService) Register(req RegisterRequest, ipAddress, userAgent string) (*AuthResponse, error) {
// Check if email already exists
existingUser, _ := s.userRepo.FindByEmail(req.Email)
if existingUser != nil {
return nil, errors.New("email already registered")
}
// Check if NRP already exists
if req.NRP != "" {
existingNRP, _ := s.userRepo.FindByNRP(req.NRP)
if existingNRP != nil {
return nil, errors.New("NRP already registered")
}
}
// Hash password
hashedPassword, err := utils.HashPassword(req.Password)
if err != nil {
return nil, errors.New("failed to hash password")
}
// Get user role ID
userRole, err := s.roleRepo.FindByName(models.RoleUser)
if err != nil {
return nil, errors.New("failed to get user role")
}
// Create user
user := &models.User{
Name: req.Name,
Email: req.Email,
Password: hashedPassword,
NRP: req.NRP,
Phone: req.Phone,
RoleID: userRole.ID,
Status: "active",
}
if err := s.userRepo.Create(user); err != nil {
return nil, errors.New("failed to create user")
}
// Load user with role
user, err = s.userRepo.FindByID(user.ID)
if err != nil {
return nil, err
}
// Generate JWT token
token, err := config.GenerateToken(user.ID, user.Email, user.Role.Name)
if err != nil {
return nil, errors.New("failed to generate token")
}
// Log audit
s.auditLogRepo.Log(&user.ID, models.ActionCreate, models.EntityUser, &user.ID,
"User registered", ipAddress, userAgent)
return &AuthResponse{
Token: token,
User: user.ToResponse(),
}, nil
}
// Login authenticates a user
func (s *AuthService) Login(req LoginRequest, ipAddress, userAgent string) (*AuthResponse, error) {
// Find user by email
user, err := s.userRepo.FindByEmail(req.Email)
if err != nil {
return nil, errors.New("invalid email or password")
}
// Check if user is blocked
if user.IsBlocked() {
return nil, errors.New("account is blocked")
}
// Verify password
if !utils.CheckPasswordHash(req.Password, user.Password) {
return nil, errors.New("invalid email or password")
}
// Generate JWT token
token, err := config.GenerateToken(user.ID, user.Email, user.Role.Name)
if err != nil {
return nil, errors.New("failed to generate token")
}
// Log audit
s.auditLogRepo.Log(&user.ID, models.ActionLogin, models.EntityUser, &user.ID,
"User logged in", ipAddress, userAgent)
return &AuthResponse{
Token: token,
User: user.ToResponse(),
}, nil
}
// ValidateToken validates JWT token and returns user
func (s *AuthService) ValidateToken(tokenString string) (*models.User, error) {
// Validate token
claims, err := config.ValidateToken(tokenString)
if err != nil {
return nil, errors.New("invalid token")
}
// Get user
user, err := s.userRepo.FindByID(claims.UserID)
if err != nil {
return nil, errors.New("user not found")
}
// Check if user is blocked
if user.IsBlocked() {
return nil, errors.New("account is blocked")
}
return user, nil
}
// RefreshToken refreshes JWT token
func (s *AuthService) RefreshToken(oldToken string) (string, error) {
return config.RefreshToken(oldToken)
}