// 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 }