diff --git a/src/main/java/com/devoops/accommodation/grpc/AccommodationGrpcService.java b/src/main/java/com/devoops/accommodation/grpc/AccommodationGrpcService.java index 2f13bc0..301e1d6 100644 --- a/src/main/java/com/devoops/accommodation/grpc/AccommodationGrpcService.java +++ b/src/main/java/com/devoops/accommodation/grpc/AccommodationGrpcService.java @@ -3,11 +3,10 @@ import com.devoops.accommodation.entity.Accommodation; import com.devoops.accommodation.entity.AvailabilityPeriod; import com.devoops.accommodation.entity.PricingMode; -import com.devoops.accommodation.grpc.proto.AccommodationInternalServiceGrpc; -import com.devoops.accommodation.grpc.proto.ReservationValidationRequest; -import com.devoops.accommodation.grpc.proto.ReservationValidationResponse; +import com.devoops.accommodation.grpc.proto.*; import com.devoops.accommodation.repository.AccommodationRepository; import com.devoops.accommodation.repository.AvailabilityPeriodRepository; +import com.devoops.accommodation.service.AccommodationService; import io.grpc.stub.StreamObserver; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -27,6 +26,7 @@ public class AccommodationGrpcService extends AccommodationInternalServiceGrpc.A private final AccommodationRepository accommodationRepository; private final AvailabilityPeriodRepository availabilityPeriodRepository; + private final AccommodationService accommodationService; @Override public void validateAndCalculatePrice( @@ -126,4 +126,43 @@ private ReservationValidationResponse buildErrorResponse(String errorCode, Strin .setErrorMessage(errorMessage) .build(); } + + @Override + public void deleteAccommodationsByHost(DeleteByHostRequest request, + StreamObserver responseObserver) { + log.debug("gRPC: Deleting all accommodations for host: {}", request.getHostId()); + + try { + UUID hostId = UUID.fromString(request.getHostId()); + int deletedCount = accommodationService.deleteAllByHostId(hostId); + + log.info("Deleted {} accommodations for host {}", deletedCount, hostId); + + DeleteByHostResponse response = DeleteByHostResponse.newBuilder() + .setSuccess(true) + .setDeletedCount(deletedCount) + .build(); + + responseObserver.onNext(response); + responseObserver.onCompleted(); + } catch (IllegalArgumentException e) { + log.error("Invalid host ID format: {}", request.getHostId(), e); + DeleteByHostResponse response = DeleteByHostResponse.newBuilder() + .setSuccess(false) + .setDeletedCount(0) + .setErrorMessage("Invalid host ID format") + .build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } catch (Exception e) { + log.error("Failed to delete accommodations for host {}", request.getHostId(), e); + DeleteByHostResponse response = DeleteByHostResponse.newBuilder() + .setSuccess(false) + .setDeletedCount(0) + .setErrorMessage("Failed to delete accommodations: " + e.getMessage()) + .build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } + } } diff --git a/src/main/java/com/devoops/accommodation/repository/AccommodationRepository.java b/src/main/java/com/devoops/accommodation/repository/AccommodationRepository.java index 8b78295..a7e3875 100644 --- a/src/main/java/com/devoops/accommodation/repository/AccommodationRepository.java +++ b/src/main/java/com/devoops/accommodation/repository/AccommodationRepository.java @@ -4,9 +4,11 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.time.LocalDateTime; import java.util.List; import java.util.UUID; @@ -24,4 +26,19 @@ WHERE LOWER(a.address) LIKE LOWER(CONCAT('%', :location, '%')) List searchByLocationAndGuests( @Param("location") String location, @Param("guests") int guests); + + /** + * Soft delete all accommodations for a host. + * Used when host deletes their account. + * + * @return the number of accommodations soft-deleted + */ + @Modifying + @Query(""" + UPDATE Accommodation a + SET a.isDeleted = true, a.updatedAt = :now + WHERE a.hostId = :hostId + AND a.isDeleted = false + """) + int softDeleteByHostId(@Param("hostId") UUID hostId, @Param("now") LocalDateTime now); } diff --git a/src/main/java/com/devoops/accommodation/service/AccommodationService.java b/src/main/java/com/devoops/accommodation/service/AccommodationService.java index 9233b60..0ea7fe7 100644 --- a/src/main/java/com/devoops/accommodation/service/AccommodationService.java +++ b/src/main/java/com/devoops/accommodation/service/AccommodationService.java @@ -24,6 +24,7 @@ import java.math.BigDecimal; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; @@ -115,6 +116,18 @@ public void delete(UUID id, UserContext userContext) { accommodationRepository.save(accommodation); } + /** + * Soft delete all accommodations owned by a host. + * Used when a host deletes their account (cascade deletion). + * + * @param hostId the ID of the host whose accommodations should be deleted + * @return the number of accommodations soft-deleted + */ + @Transactional + public int deleteAllByHostId(UUID hostId) { + return accommodationRepository.softDeleteByHostId(hostId, LocalDateTime.now()); + } + @Transactional(readOnly = true) public Page search(String location, int guests, LocalDate startDate, LocalDate endDate, int page, int size) { if (!endDate.isAfter(startDate)) { diff --git a/src/main/proto/accommodation_internal.proto b/src/main/proto/accommodation_internal.proto index 86bc71f..fa227cd 100644 --- a/src/main/proto/accommodation_internal.proto +++ b/src/main/proto/accommodation_internal.proto @@ -6,6 +6,7 @@ option java_package = "com.devoops.accommodation.grpc.proto"; service AccommodationInternalService { rpc ValidateAndCalculatePrice(ReservationValidationRequest) returns (ReservationValidationResponse); + rpc DeleteAccommodationsByHost(DeleteByHostRequest) returns (DeleteByHostResponse); } message ReservationValidationRequest { @@ -25,3 +26,13 @@ message ReservationValidationResponse { string approval_mode = 7; string accommodation_name = 8; } + +message DeleteByHostRequest { + string host_id = 1; +} + +message DeleteByHostResponse { + bool success = 1; + int32 deleted_count = 2; + string error_message = 3; +}