2025-11-23 22:49:46 +07:00

191 lines
5.1 KiB
Go

// internal/services/user_service.go
package services
import (
"errors"
"lost-and-found/internal/models"
"lost-and-found/internal/repositories"
"lost-and-found/internal/utils"
"gorm.io/gorm"
)
type UserService struct {
userRepo *repositories.UserRepository
roleRepo *repositories.RoleRepository
auditLogRepo *repositories.AuditLogRepository
}
func NewUserService(db *gorm.DB) *UserService {
return &UserService{
userRepo: repositories.NewUserRepository(db),
roleRepo: repositories.NewRoleRepository(db),
auditLogRepo: repositories.NewAuditLogRepository(db),
}
}
// UpdateProfileRequest represents profile update data
type UpdateProfileRequest struct {
Name string `json:"name"`
Phone string `json:"phone"`
NRP string `json:"nrp"`
}
// ChangePasswordRequest represents password change data
type ChangePasswordRequest struct {
OldPassword string `json:"old_password" binding:"required"`
NewPassword string `json:"new_password" binding:"required,min=6"`
}
// GetProfile gets user profile
func (s *UserService) GetProfile(userID uint) (*models.User, error) {
return s.userRepo.FindByID(userID)
}
// UpdateProfile updates user profile
func (s *UserService) UpdateProfile(userID uint, req UpdateProfileRequest, ipAddress, userAgent string) (*models.User, error) {
user, err := s.userRepo.FindByID(userID)
if err != nil {
return nil, err
}
// Update fields
if req.Name != "" {
user.Name = req.Name
}
if req.Phone != "" {
user.Phone = req.Phone
}
if req.NRP != "" {
// Check if NRP already exists for another user
existingNRP, _ := s.userRepo.FindByNRP(req.NRP)
if existingNRP != nil && existingNRP.ID != userID {
return nil, errors.New("NRP already used by another user")
}
user.NRP = req.NRP
}
if err := s.userRepo.Update(user); err != nil {
return nil, errors.New("failed to update profile")
}
// Log audit
s.auditLogRepo.Log(&userID, models.ActionUpdate, models.EntityUser, &userID,
"Profile updated", ipAddress, userAgent)
return user, nil
}
// ChangePassword changes user password
func (s *UserService) ChangePassword(userID uint, req ChangePasswordRequest, ipAddress, userAgent string) error {
user, err := s.userRepo.FindByID(userID)
if err != nil {
return err
}
// Verify old password
if !utils.CheckPasswordHash(req.OldPassword, user.Password) {
return errors.New("invalid old password")
}
// Hash new password
hashedPassword, err := utils.HashPassword(req.NewPassword)
if err != nil {
return errors.New("failed to hash password")
}
user.Password = hashedPassword
if err := s.userRepo.Update(user); err != nil {
return errors.New("failed to change password")
}
// Log audit
s.auditLogRepo.Log(&userID, models.ActionUpdate, models.EntityUser, &userID,
"Password changed", ipAddress, userAgent)
return nil
}
// GetUserStats gets user statistics
func (s *UserService) GetUserStats(userID uint) (map[string]interface{}, error) {
return s.userRepo.GetUserStats(userID)
}
// GetAllUsers gets all users (admin only)
func (s *UserService) GetAllUsers(page, limit int) ([]models.User, int64, error) {
return s.userRepo.FindAll(page, limit)
}
// GetUserByID gets user by ID (admin only)
func (s *UserService) GetUserByID(id uint) (*models.User, error) {
return s.userRepo.FindByID(id)
}
// UpdateUserRole updates user role (admin only)
func (s *UserService) UpdateUserRole(adminID, userID, roleID uint, ipAddress, userAgent string) error {
// Verify role exists
role, err := s.roleRepo.FindByID(roleID)
if err != nil {
return errors.New("invalid role")
}
// Update role
if err := s.userRepo.UpdateRole(userID, roleID); err != nil {
return errors.New("failed to update user role")
}
// Log audit
s.auditLogRepo.Log(&adminID, models.ActionUpdate, models.EntityUser, &userID,
"Role updated to: "+role.Name, ipAddress, userAgent)
return nil
}
// BlockUser blocks a user (admin only)
func (s *UserService) BlockUser(adminID, userID uint, ipAddress, userAgent string) error {
// Cannot block self
if adminID == userID {
return errors.New("cannot block yourself")
}
if err := s.userRepo.BlockUser(userID); err != nil {
return errors.New("failed to block user")
}
// Log audit
s.auditLogRepo.Log(&adminID, models.ActionBlock, models.EntityUser, &userID,
"User blocked", ipAddress, userAgent)
return nil
}
// UnblockUser unblocks a user (admin only)
func (s *UserService) UnblockUser(adminID, userID uint, ipAddress, userAgent string) error {
if err := s.userRepo.UnblockUser(userID); err != nil {
return errors.New("failed to unblock user")
}
// Log audit
s.auditLogRepo.Log(&adminID, models.ActionUnblock, models.EntityUser, &userID,
"User unblocked", ipAddress, userAgent)
return nil
}
// DeleteUser deletes a user (admin only)
func (s *UserService) DeleteUser(adminID, userID uint, ipAddress, userAgent string) error {
// Cannot delete self
if adminID == userID {
return errors.New("cannot delete yourself")
}
if err := s.userRepo.Delete(userID); err != nil {
return errors.New("failed to delete user")
}
// Log audit
s.auditLogRepo.Log(&adminID, models.ActionDelete, models.EntityUser, &userID,
"User deleted", ipAddress, userAgent)
return nil
}