package it.bgates.remotebe.service; import it.bgates.remotebe.entities.Device; import it.bgates.remotebe.entities.Phone; import it.bgates.remotebe.entities.User; import it.bgates.remotebe.exception.*; import it.bgates.remotebe.repository.PhoneRepository; import it.bgates.remotebe.repository.UserRepository; import jakarta.persistence.EntityManager; import jakarta.persistence.TypedQuery; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.security.Principal; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @Service @RequiredArgsConstructor public class PhoneService extends BaseService { private final PhoneRepository phoneRepository; private final UserRepository userRepository; private final EntityManager entityManager; // private final DeviceService deviceService; // private final BillingService billingService; //private final ConfigService configService; public List getPhonesByDeviceId(Integer deviceId, Principal principal) throws UserNotFoundException, NotFoundException { /* Device device = deviceService.getDevice(deviceId, principal); if (device == null) { throw new NotFoundException("Device not found"); } */ return phoneRepository.findByDeviceId(deviceId); } @Transactional public Phone addPhone(@Valid Phone phone, Principal principal) throws UserNotFoundException, InvalidBillingTypeException, InsufficientCreditException, AlreadyPresentException, NullValueNotAllowed { if (phone.getDevice() == null) { throw new NullValueNotAllowed("Dispositivo non specificato"); } // del numero di telefono tieni solo le cifre e il carattere + phone.setPhoneNumber(phone.getPhoneNumber().replaceAll("[^0-9+]", "")); if (phone.getId() == null) { /* if (!billingService.sufficientBalance(principal, configService.getBillingTypeCost(BillingType.USER_ADD))) { throw new InsufficientCreditException("Saldo GT-Coins insufficiente per effettuare l'operazione"); } */ // check if the same phone number is already present in the device int cnt = phoneRepository.countPhones(phone.getDevice().getId(), phone.getPhoneNumber()); if (cnt > 9) { throw new AlreadyPresentException("Numero di telefono giĆ  presente nel dispositivo"); } phone.setCreateDate(LocalDateTime.now()); } if (phone.getDeleted() == null) { phone.setDeleted(false); } phone.setModified(true); phone.setSynched(false); Phone addedPhone = phoneRepository.save(phone); /* billingService.addBilling(principal, phone.getDevice(), BillingType.USER_ADD, String.format( "Aggiunto numero %s", phone.getPhoneNumber() ) ); */ return addedPhone; } public List filter(Integer deviceId, String filter, Principal principal) throws UserNotFoundException { getUserDetails(principal); Optional user = userRepository.findByUsername(userDetails.getUsername()); if (user.isEmpty()) { return List.of(); } StringBuilder filterBuilder = new StringBuilder(); String join = ""; if (isSuperUser()) { filterBuilder.append("WHERE true "); } else if (isDistributor()) { filterBuilder.append("join device d on d.id = p.device.id "); filterBuilder.append("WHERE d.distributor = :distributor"); } else if (isUser()) { filterBuilder.append("join device d on d.id = p.device.id "); filterBuilder.append("join p.device.owner o on o.id = p.device.owner.id "); filterBuilder.append("WHERE o.id=:ownerId "); } else { filterBuilder.append("WHERE false "); } if (deviceId != null) { filterBuilder.append(join).append("and p.device.id=:deviceId "); } List params = buildFilter(filterBuilder, filter, new String[]{ "p.phoneNumber", "p.description" }); String sql = "SELECT p FROM Phone p " + System.lineSeparator() + filterBuilder + System.lineSeparator() + " ORDER BY p.description"; TypedQuery query = entityManager.createQuery(sql, Phone.class); for (int i = 0; i < params.size(); i++) { query.setParameter("param_" + i, params.get(i)); } if (isDistributor()) { query.setParameter("distributor", user.get().getDistributor()); } else if (isUser()) { query.setParameter("ownerId", user.get().getId()); } if (deviceId != null) { query.setParameter("deviceId", deviceId); } List phones = query.getResultList(); return phones; } public Boolean deactivatePhone(Integer phoneId, Principal principal) throws NotFoundException, UserNotFoundException, PermissionDeniedException { getUserDetails(principal); Optional user = userRepository.findByUsername(userDetails.getUsername()); if (user.isEmpty()) { throw new UserNotFoundException("Utente non trovato"); } Phone phoneToDeactivate = checkDeviceAccessibleToUser(phoneId, user.get()); Optional phone = phoneRepository.findById(phoneId); if (phone.isPresent()) { phone.get().setActive(false); phone.get().setSynched(false); phone.get().setModified(true); phoneRepository.save(phone.get()); return true; } throw new NotFoundException("Telefono non trovato"); } /** * Marks the phone for deletion after verifying user access and permissions. * * @param id The ID of the phone to be deleted. * @param principal The security principal of the currently authenticated user. * @return A boolean value indicating whether the phone was successfully marked as deleted. * @throws UserNotFoundException If the authenticated user could not be found. * @throws PermissionDeniedException If the user does not have permission to access the phone. * @throws NotFoundException If the phone with the specified ID does not exist. */ public boolean deletePhones(Integer id, Principal principal) throws UserNotFoundException, PermissionDeniedException, NotFoundException { getUserDetails(principal); Optional user = userRepository.findByUsername(userDetails.getUsername()); if (user.isEmpty()) { throw new UserNotFoundException("Utente non trovato"); } if (phoneRepository.findById(id).isEmpty()) { throw new NotFoundException("Telefono non trovato"); } Phone phoneToDelete = checkDeviceAccessibleToUser(id, user.get()); phoneToDelete.setDeleted(true); phoneToDelete.setSynched(false); phoneToDelete.setDeletionTime(LocalDateTime.now()); phoneRepository.save(phoneToDelete); return true; } /** * Checks if the device that has the phone is accessible to the given user based on their role and permissions. * This method executes a query to retrieve a phone entity based on the user's access level * and the provided ID. If the user does not have permission to access the device, * a {@link PermissionDeniedException} is thrown. * * @param id the ID of the phone to be checked. * @param user an {@code Optional} representing the current logged-in user requesting access. * The user parameter is required to determine the level of permissions. * @return the {@code Phone} entity that the user has access to if permitted. * @throws PermissionDeniedException if the user is not allowed to manage the specified phone. */ private Phone checkDeviceAccessibleToUser(Integer id, User user) throws PermissionDeniedException { // Check if user has access to phone StringBuilder filterBuilder = new StringBuilder(); String join = ""; if (isSuperUser()) { filterBuilder.append("WHERE phone.id = :id "); } else if (isDistributor()) { filterBuilder.append("join device d on d.id = phone.device.id "); filterBuilder.append("WHERE d.distributor = :distributor and phone.id = :id"); } else if (isUser()) { filterBuilder.append("join device d on d.id = phone.device.id "); filterBuilder.append("join phone.device.owner o on o.id = phone.device.owner.id "); filterBuilder.append("WHERE o.id=:ownerId and phone.id=:id "); } else { filterBuilder.append("WHERE false "); } String sql = "SELECT phone FROM Phone phone " + System.lineSeparator() + filterBuilder + System.lineSeparator(); TypedQuery query = entityManager.createQuery(sql, Phone.class); query.setParameter("id", id); if (isDistributor()) { query.setParameter("distributor", user.getDistributor()); } else if (isUser()) { query.setParameter("ownerId", user.getId()); } List phones = query.getResultList(); if (phones.isEmpty()) { throw new PermissionDeniedException("Utente non autorizzato a gestire il telefono specificato"); } return phones.getFirst(); } public Boolean activatePhone(Integer phoneId, Principal principal) throws NotFoundException, UserNotFoundException, PermissionDeniedException { getUserDetails(principal); Optional user = userRepository.findByUsername(userDetails.getUsername()); if (user.isEmpty()) { throw new UserNotFoundException("Utente non trovato"); } if (phoneRepository.findById(phoneId).isEmpty()) { throw new NotFoundException("Telefono non trovato"); } Phone phone = checkDeviceAccessibleToUser(phoneId, user.get()); phone.setActive(true); phoneRepository.save(phone); return true; } public List getDeletedPhones(Device device) { return phoneRepository.findDeletedPhoneByDevice(device.getId()); } public List getModifiedPhones(Device device) { return phoneRepository.findModifiedPhoneByDevice(device.getId()); } public void delete(Integer id) { phoneRepository.deleteById(id); } public void clearUserModifiedFlags(Integer id) { phoneRepository.clearUserModifiedFlags(id); } }