Changes between Initial Version and Version 1 of Advanced Application Development


Ignore:
Timestamp:
02/21/26 16:34:01 (7 days ago)
Author:
231035
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Advanced Application Development

    v1 v1  
     1= Advanced Application Development
     2== Transactional
     3=== Adding a listing as a favorite
     4{{{
     5@Transactional
     6    public void addFavorite(Long userId, Long listingId) {
     7        Client client = clientRepository.findByUserId(userId)
     8            .orElseThrow(() -> new RuntimeException("Client not found"));
     9
     10        Listing listing = listingRepository.findById(listingId)
     11            .orElseThrow(() -> new RuntimeException("Listing not found"));
     12
     13        FavoriteListing favorite = new FavoriteListing(client, listing);
     14        favoriteRepository.save(favorite);
     15        logger.info("Added favorite - User: {}, Listing: {}", userId, listingId);
     16    }
     17}}}
     18=== Removing a listing from favorites
     19{{{
     20@Transactional
     21    public void removeFavorite(Long userId, Long listingId) {
     22        Client client = clientRepository.findByUserId(userId)
     23            .orElseThrow(() -> new RuntimeException("Client not found"));
     24
     25        Listing listing = listingRepository.findById(listingId)
     26            .orElseThrow(() -> new RuntimeException("Listing not found"));
     27
     28        FavoriteListing favorite = favoriteRepository.findByClientAndListing(client, listing)
     29            .orElseThrow(() -> new RuntimeException("Favorite not found"));
     30
     31        favoriteRepository.delete(favorite);
     32        logger.info("Removed favorite - User: {}, Listing: {}", userId, listingId);
     33    }
     34}}}
     35=== Getting information from the favorite_listings table
     36{{{
     37    @Transactional(readOnly = true)
     38    public List<ListingDTO> getFavoritedListings(Long userId) {
     39        return favoriteRepository.findFavoritedListingDTOs(userId);
     40    }
     41
     42    @Transactional(readOnly = true)
     43    public boolean isFavorited(Long userId, Long listingId) {
     44        Client client = clientRepository.findByUserId(userId)
     45            .orElse(null);
     46
     47        if (client == null) return false;
     48
     49        Listing listing = listingRepository.findById(listingId)
     50            .orElse(null);
     51
     52        if (listing == null) return false;
     53
     54        return favoriteRepository.findByClientAndListing(client, listing).isPresent();
     55    }
     56}}}
     57=== Creating a review
     58{{{
     59@Transactional
     60    public ReviewDTO createReview(Long reviewerId, Long targetUserId, CreateReviewRequest request) {
     61        logger.info("==== START createReview ====");
     62        // Validate rating
     63        if (request.getRating() == null || request.getRating() < 1 || request.getRating() > 5) {
     64            logger.error(" VALIDATION FAILED: Invalid rating: {}", request.getRating());
     65            throw new RuntimeException("Rating must be between 1 and 5");
     66        }
     67     
     68
     69        // Check if reviewer exists
     70        User reviewer = userRepository.findById(reviewerId)
     71                .orElseThrow(() -> {
     72                    logger.error(" Reviewer not found with ID: {}", reviewerId);
     73                    return new RuntimeException("Reviewer not found");
     74                });
     75
     76        // Check if target user exists
     77        User targetUser = userRepository.findById(targetUserId)
     78                .orElseThrow(() -> {
     79                    logger.error(" Target user not found with ID: {}", targetUserId);
     80                    return new RuntimeException("Target user not found");
     81                });
     82
     83        // Check if review already exists and is not deleted
     84        logger.info("Checking if reviewer {} has already reviewed user {}", reviewerId, targetUserId);
     85        var existingReview = userReviewRepository.findTopByReviewReviewerUserIdAndTargetUserIdAndReviewIsDeletedFalseOrderByReviewCreatedAtDesc(reviewerId, targetUserId);
     86
     87        if (existingReview.isPresent()) {
     88            Review existingReviewEntity = existingReview.get().getReview();
     89            logger.info("Found existing review with ID: {}", existingReviewEntity.getReviewId());
     90            logger.info("Existing review isDeleted status: {}", existingReviewEntity.getIsDeleted());
     91
     92            if (!existingReviewEntity.getIsDeleted()) {
     93                logger.error(" User {} has already reviewed user {} and review is NOT deleted", reviewerId, targetUserId);
     94                throw new RuntimeException("You have already reviewed this user");
     95            } else {
     96                logger.info(" User {} has a deleted review for user {} - can create a new one", reviewerId, targetUserId);
     97            }
     98        } else {
     99            logger.info(" No existing review found - safe to create new review");
     100        }
     101
     102        // Create Review entity
     103        Review review = new Review(reviewer, request.getRating(), request.getComment());
     104
     105
     106        // Save Review to database with flush
     107        review = reviewRepository.saveAndFlush(review);
     108        logger.info("Review ID after save: {}", review.getReviewId());
     109
     110        if (review.getReviewId() == null) {
     111            logger.error(" CRITICAL: Review ID is NULL after save!");
     112            throw new RuntimeException("Failed to save review - ID is null");
     113        }
     114
     115        // Create UserReview entry
     116        UserReview userReview = new UserReview();
     117        logger.info("Setting Review on UserReview (will copy ID via @MapsId)...");
     118        userReview.setReview(review);
     119        logger.info("UserReview reviewId after setReview: {}", userReview.getReviewId());
     120
     121        userReview.setTargetUserId(targetUserId);
     122
     123        // Save UserReview to database with flush
     124        userReview = userReviewRepository.saveAndFlush(userReview);
     125        logger.info(" UserReview saved successfully");
     126
     127        // Create and return DTO
     128        ReviewDTO reviewDTO = new ReviewDTO(review);
     129        logger.info(" ReviewDTO created successfully");
     130
     131        return reviewDTO;
     132    }
     133}}}
     134=== Deleting a review
     135{{{
     136@Transactional
     137    public void deleteReview(Long reviewId, Long userId) {
     138        logger.info("=== START deleteReview (SOFT DELETE) ===");
     139       
     140
     141        // Fetch review
     142        logger.info("Fetching review with ID: {}", reviewId);
     143        Review review = reviewRepository.findById(reviewId)
     144                .orElseThrow(() -> {
     145                    logger.error(" Review not found with ID: {}", reviewId);
     146                    return new RuntimeException("Review not found");
     147                });
     148        logger.info(" Review found: reviewer={}, rating={}", review.getReviewer().getUsername(), review.getRating());
     149
     150        // Check authorization
     151        if (!review.getReviewer().getUserId().equals(userId)) {
     152            logger.error(" User {} is not authorized to delete review {}. Reviewer is {}", userId, reviewId, review.getReviewer().getUserId());
     153            throw new RuntimeException("You can only delete your own reviews");
     154        }
     155
     156        // Soft delete: mark as deleted instead of physically removing
     157        review.setIsDeleted(true);
     158        review.setUpdatedAt(LocalDateTime.now());
     159        reviewRepository.save(review);
     160
     161        logger.info("=== END deleteReview - SUCCESS ===");
     162    }
     163}}}
     164=== Creating a new pet
     165{{{
     166@Transactional
     167    public AnimalResponseDTO addPet(Long userId,@RequestBody CreatePetRequest request) {
     168
     169        // Validate required fields
     170        if (request.getName() == null || request.getName().isBlank()) {
     171            throw new RuntimeException("Pet name is required");
     172        }
     173
     174        if (request.getSex() == null || request.getSex().isBlank()) {
     175            throw new RuntimeException("Pet sex is required");
     176        }
     177
     178        if (request.getType() == null || request.getType().isBlank()) {
     179            throw new RuntimeException("Pet type is required");
     180        }
     181
     182
     183        if (request.getSpecies() == null || request.getSpecies().isBlank()) {
     184            throw new RuntimeException("Pet species is required");
     185        }
     186
     187        // Get user
     188        User user = userRepository.findById(userId)
     189                .orElseThrow(() -> {
     190                    logger.error(" User not found with ID: {}", userId);
     191                    return new RuntimeException("User not found");
     192                });
     193
     194        logger.info("Adding pet for user ID: {}", userId);
     195
     196        // Check if user is already an owner, if not, promote them
     197        Owner owner = ownerRepository.findByUserId(userId)
     198                .orElseGet(() -> {
     199                    logger.info("⚠User {} is a CLIENT, promoting to OWNER", userId);
     200                    Owner newOwner = new Owner(user);
     201                    Owner savedOwner = ownerRepository.save(newOwner);
     202                    logger.info(" User promoted to OWNER with ID: {}", savedOwner.getUserId());
     203                    return savedOwner;
     204                });
     205
     206        // Create new pet with all schema fields
     207
     208        Pet pet = new Pet(
     209                request.getName(),
     210                request.getSex(),
     211                request.getDateOfBirth(),
     212                request.getPhotoUrl(),
     213                request.getType(),
     214                request.getSpecies(),
     215                request.getBreed(),
     216                request.getLocatedName(),
     217                owner
     218        );
     219       
     220        Pet savedPet = petRepository.save(pet);
     221        logger.info("Pet ID: {}, Owner ID: {}, Name: {}",
     222                savedPet.getAnimalId(), userId, savedPet.getName());
     223
     224        AnimalResponseDTO result = new AnimalResponseDTO(savedPet);
     225
     226
     227        return result;
     228    }
     229}}}
     230=== Creating a new listing
     231{{{
     232   @Transactional
     233    public ListingDTO createListing(Long userId, CreateListingRequest request) {
     234        // Check if user is an owner
     235        Owner owner = ownerRepository.findByUserId(userId)
     236            .orElseThrow(() -> new RuntimeException("User is not an owner. Only owners can create listings."));
     237
     238        logger.info("Creating listing for owner ID: {}", userId);
     239
     240        // Create new listing with Owner object
     241        Listing listing = new Listing(
     242            owner,
     243            request.getAnimalId(),
     244            request.getPrice(),
     245            request.getDescription()
     246        );
     247
     248        Listing savedListing = listingRepository.save(listing);
     249
     250        logger.info("Listing created successfully - ID: {}, Owner ID: {}, Animal ID: {}",
     251            savedListing.getListingId(), userId, request.getAnimalId());
     252
     253        return mapToDTO(savedListing);
     254    }
     255}}}