190 lines
5.1 KiB
Go
190 lines
5.1 KiB
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
|
|
} |