Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import lombok.RequiredArgsConstructor;
import org.atdev.artrip.domain.Enum.KeywordType;
import org.atdev.artrip.domain.Enum.SortType;
import org.atdev.artrip.domain.Enum.Status;
import org.atdev.artrip.domain.exhibit.data.Exhibit;
import org.atdev.artrip.domain.exhibit.data.QExhibit;
import org.atdev.artrip.domain.exhibit.web.dto.request.ExhibitFilterRequestDto;
Expand Down Expand Up @@ -64,6 +65,7 @@ public Slice<Exhibit> findExhibitByFilters(ExhibitFilterRequestDto dto, Pageable
.leftJoin(e.keywords, k)
.leftJoin(f).on(f.exhibit.eq(e))
.where(
e.status.ne(Status.FINISHED),
typeFilter(dto, h),
dateFilter(dto.getStartDate(), dto.getEndDate(),e),
cursorCondition(cursor, cursorFavoriteCount, dto.getSortType(), e, f),
Expand Down Expand Up @@ -92,7 +94,7 @@ public List<HomeListResponse> findRandomExhibits(RandomExhibitRequest c) {
QKeyword k = QKeyword.keyword;

return queryFactory
.selectDistinct(Projections.constructor(
.selectDistinct(Projections.constructor(// select 순서와 DTO 생성자 파라미터 순서를 1:1 매핑함!
HomeListResponse.class,
e.exhibitId,
e.title,
Expand All @@ -103,12 +105,15 @@ public List<HomeListResponse> findRandomExhibits(RandomExhibitRequest c) {
e.startDate.stringValue(),
e.endDate.stringValue()
),
h.name
h.name,
h.country,
h.region
))
.from(e)
.join(e.exhibitHall, h)
.leftJoin(e.keywords, k)
.where(
e.status.ne(Status.FINISHED),
isDomesticEq(c.getIsDomestic()),
countryEq(c.getCountry()),
regionEq(c.getRegion()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class FavoriteExhibit {
@JoinColumn(name = "user_id", nullable = false)
private User user;

@Column(nullable = false)
private boolean status = false;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "exhibit_id", nullable = false)
private Exhibit exhibit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,80 @@
import java.util.Optional;

public interface FavoriteExhibitRepository extends JpaRepository<FavoriteExhibit, Long> {
boolean existsByUser_UserIdAndExhibit_ExhibitId(Long userId, Long exhibitId);
@Query("""
SELECT COUNT(f) > 0
FROM FavoriteExhibit f
WHERE f.user.userId = :userId
AND f.exhibit.exhibitId = :exhibitId
And f.status = true
""")
boolean existsActive(@Param("userId") Long userId, @Param("exhibitId") Long exhibitId);

@Query("SELECT f FROM FavoriteExhibit f " +
@Query("SELECT f " +
"FROM FavoriteExhibit f " +
"INNER JOIN FETCH f.exhibit e " +
"INNER JOIN FETCH e.exhibitHall " +
"WHERE f.user.userId = :userId " +
"AND f.status = true " +
"ORDER BY f.createdAt DESC ")
List<FavoriteExhibit> findAllByUserIdWithExhibit(@Param("userId") Long userId);
List<FavoriteExhibit> findAllActive(@Param("userId") Long userId);

@Query("SELECT f FROM FavoriteExhibit f " +
@Query("SELECT f " +
"FROM FavoriteExhibit f " +
"INNER JOIN FETCH f.exhibit e " +
"INNER JOIN fetch e.exhibitHall eh " +
"WHERE f.user.userId = :userId " +
"AND f.status = true " +
"AND DATE(e.startDate) <= :date " +
"AND DATE(e.endDate) >= :date " +
"ORDER BY e.startDate ASC")
List<FavoriteExhibit> findByUserIdAndDate(@Param("userId") Long userId, @Param("date") LocalDate date);
List<FavoriteExhibit> findActiveByDate(@Param("userId") Long userId, @Param("date") LocalDate date);

@Query("SELECT f FROM FavoriteExhibit f " +
@Query("SELECT f " +
"FROM FavoriteExhibit f " +
"INNER JOIN f.exhibit e " +
"INNER JOIN e.exhibitHall eh " +
"WHERE f.user.userId = :userId " +
"AND f.status = true " +
"AND eh.country = :country " +
"ORDER BY e.startDate DESC")
List<FavoriteExhibit> findByUserIdAndCountry(@Param("userId") Long userId, @Param("country") String country);
List<FavoriteExhibit> findActiveByCountry(@Param("userId") Long userId, @Param("country") String country);

@Query(value = "SELECT DISTINCT DATE(e.start_date) " +
"FROM favorite_exhibit f " +
"INNER JOIN exhibit e ON f.exhibit_id = e.exhibit_id " +
"WHERE f.user_id = :userId " +
"AND f.status = true " +
"AND YEAR (e.start_date) = :year " +
"AND MONTH (e.start_date) = :month " +
"ORDER BY DATE(e.start_date) ASC", nativeQuery = true)
List<String> findExhibitDatesByUserIdAndYearMonth(
List<String> findDatesByYearMonth(
@Param("userId") Long userId,
@Param("year") int year,
@Param("month") int month);

@Query("SELECT DISTINCT eh.country FROM FavoriteExhibit f " +
@Query("SELECT DISTINCT eh.country " +
"FROM FavoriteExhibit f " +
"INNER JOIN f.exhibit e " +
"INNER JOIN e.exhibitHall eh " +
"WHERE f.user.userId = :userId " +
"AND f.status = true " +
"AND eh.country IS NOT NULL " +
"ORDER BY eh.country ASC")
List<String> findDistinctCountriesByUserId(@Param("userId") Long userId);
List<String> findDistinctCountries(@Param("userId") Long userId);

@Query("SELECT f FROM FavoriteExhibit f " +
@Query("SELECT f " +
"FROM FavoriteExhibit f " +
"WHERE f.user.userId = :userId " +
"AND f.exhibit.exhibitId = :exhibitId")
Optional<FavoriteExhibit> findByUserIdAndExhibitId(@Param("userId") Long userId, @Param("exhibitId") Long exhibitId);
"AND f.exhibit.exhibitId = :exhibitId " +
"AND f.status = true")
Optional<FavoriteExhibit> findActive(@Param("userId") Long userId, @Param("exhibitId") Long exhibitId);

@Query("""
SELECT f
FROM FavoriteExhibit f
WHERE f.user.userId = :userId
AND f.exhibit.exhibitId = :exhibitId
""")
Optional<FavoriteExhibit> findByUserAndExhibit(@Param("userId") Long userId, @Param("exhibitId") Long exhibitId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
import org.atdev.artrip.domain.favortie.web.dto.response.CalenderResponse;
import org.atdev.artrip.domain.favortie.web.dto.response.FavoriteResponse;
import org.atdev.artrip.domain.favortie.repository.FavoriteExhibitRepository;
import org.atdev.artrip.global.apipayload.code.status.CommonError;
import org.atdev.artrip.global.apipayload.code.status.ExhibitError;
import org.atdev.artrip.global.apipayload.code.status.UserError;
import org.atdev.artrip.global.apipayload.exception.GeneralException;
import org.atdev.artrip.global.apipayload.exception.handler.ErrorHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
Expand All @@ -42,75 +41,91 @@ public FavoriteResponse addFavorite(Long userId, Long exhibitId) {

Exhibit exhibit = exhibitRepository.findById(exhibitId).orElseThrow(() -> new GeneralException(ExhibitError._EXHIBIT_NOT_FOUND));

if (favoriteExhibitRepository.existsByUser_UserIdAndExhibit_ExhibitId(userId, exhibitId)) {
log.info("Exhibit with id {} already exists", exhibitId);
throw new ErrorHandler(CommonError._BAD_REQUEST);
Optional<FavoriteExhibit> existing = favoriteExhibitRepository.findByUserAndExhibit(userId, exhibitId);

FavoriteExhibit favorite;

if (existing.isPresent()) {
favorite = existing.get();
if (favorite.isStatus()) {
log.warn("Exhibit Already in favorites: userId: {}, exhibitId: {}", userId, exhibitId);
return toFavoriteResponse(favorite);
}
favorite.setStatus(true);
log.info("Reactivating favorite exhibit: {}", favorite.getFavoriteId());
} else {
favorite = FavoriteExhibit.builder()
.user(user)
.exhibit(exhibit)
.status(true)
.createdAt(LocalDateTime.now())
.build();
log.info("Creating new favorite");
}

FavoriteExhibit favorite = FavoriteExhibit.builder()
.user(user)
.exhibit(exhibit)
.createdAt(LocalDateTime.now())
.build();
FavoriteExhibit saved = favoriteExhibitRepository.save(favorite);
log.info("Favorite exhibit added successfully. favoriteId: {}", saved.getFavoriteId());

return toFavoriteResponse(saved);
}

@Transactional(readOnly = true)
public List<FavoriteResponse> getAllFavorites(Long userId) {
log.info("Getting favorites for exhibit. userId: {}", userId);

if (!userRepository.existsById(userId)) {
throw new GeneralException(UserError._USER_NOT_FOUND);
}

List<FavoriteExhibit> favorites = favoriteExhibitRepository.findAllByUserIdWithExhibit(userId);
List<FavoriteExhibit> favorites = favoriteExhibitRepository.findAllActive(userId);
log.info("Favorites found: {}", favorites);

return favorites.stream()
.map(this::toFavoriteResponse)
.collect(Collectors.toList());
}

@Transactional(readOnly = true)
public List<FavoriteResponse> getFavoritesByDate(Long userId, LocalDate date) {
log.info("Getting favorites for exhibit by date. userID: {}, date: {}", userId, date);

if (!userRepository.existsById(userId)) {
throw new GeneralException(UserError._USER_NOT_FOUND);
}

List<FavoriteExhibit> favorites = favoriteExhibitRepository.findByUserIdAndDate(userId, date);
List<FavoriteExhibit> favorites = favoriteExhibitRepository.findActiveByDate(userId, date);
log.info("Favorites found: {}", favorites.size());

return favorites.stream()
.map(this::toFavoriteResponse)
.collect(Collectors.toList());
}

@Transactional(readOnly = true)
public List<FavoriteResponse> getFavoritesByCountry(Long userId, String country) {
log.info("Getting favorites for exhibit by country. userId: {}, country: {}", userId, country);

if (!userRepository.existsById(userId)) {
throw new GeneralException(UserError._USER_NOT_FOUND);
}

List<FavoriteExhibit> favorites = favoriteExhibitRepository.findByUserIdAndCountry(userId, country);
List<FavoriteExhibit> favorites = favoriteExhibitRepository.findActiveByCountry(userId, country);
log.info("Favorites found: {}", favorites.size());

return favorites.stream()
.map(this::toFavoriteResponse)
.collect(Collectors.toList());
}

@Transactional(readOnly = true)
public CalenderResponse getCalenderDates(Long userId, int year, int month) {
log.info("Getting calendar dates for userId: {}, year: {}, month: {}", userId, year, month);

if (!userRepository.existsById(userId)) {
throw new GeneralException(UserError._USER_NOT_FOUND);
}

List<String> dateStrings = favoriteExhibitRepository.findExhibitDatesByUserIdAndYearMonth(userId, year, month);
List<String> dateStrings = favoriteExhibitRepository.findDatesByYearMonth(userId, year, month);

List<LocalDate> exhibitDates = dateStrings.stream()
.map(LocalDate::parse)
Expand All @@ -124,29 +139,34 @@ public CalenderResponse getCalenderDates(Long userId, int year, int month) {
.build();
}

@Transactional(readOnly = true)
public List<String> getFavoriteCountries(Long userId) {
log.info("Getting favorite countries for exhibit. userId: {}", userId);

if (!userRepository.existsById(userId)) {
throw new GeneralException(UserError._USER_NOT_FOUND);
}
List<String> countries = favoriteExhibitRepository.findDistinctCountriesByUserId(userId);
List<String> countries = favoriteExhibitRepository.findDistinctCountries(userId);
log.info("Favorite countries found: {}", countries);

return countries;
}

@Transactional(readOnly = true)
public boolean isFavorite(Long userId, Long exhibitId) {
return favoriteExhibitRepository.existsByUser_UserIdAndExhibit_ExhibitId(userId, exhibitId);
return favoriteExhibitRepository.existsActive(userId, exhibitId);
}

@Transactional
public void removeFavorite(Long userId, Long exhibitId) {
log.info("Removing favorite exhibit. userId: {}, exhibitId: {}", userId, exhibitId);

FavoriteExhibit favorite = favoriteExhibitRepository.findByUserIdAndExhibitId(userId, exhibitId)
FavoriteExhibit favorite = favoriteExhibitRepository.findActive(userId, exhibitId)
.orElseThrow(() -> new GeneralException(UserError._USER_NOT_FOUND));

favoriteExhibitRepository.delete(favorite);
favorite.setStatus(false);

favoriteExhibitRepository.save(favorite);
log.info("Favorite exhibit removed successfully. favoriteId: {}", favorite.getFavoriteId());
}

Expand All @@ -161,7 +181,8 @@ private FavoriteResponse toFavoriteResponse(FavoriteExhibit favorite) {
.exhibitId(exhibit.getExhibitId())
.title(exhibit.getTitle())
.posterUrl(exhibit.getPosterUrl())
.status(exhibit.getStatus())
.exhibitStatus(exhibit.getStatus())
.favoriteStatus(favorite.isStatus())
.exhibitPeriod(period)
.exhibitHallName(hall != null ? hall.getName() : null )
.country(hall != null ? hall.getCountry() : null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class FavoriteResponse {
private Long exhibitId;
private String title;
private String posterUrl;
private Status status;
private Status exhibitStatus;
private boolean favoriteStatus;
private String exhibitPeriod;
private String exhibitHallName;
private String country;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,5 @@ private String normalize(String value) {
return value;
}


}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.atdev.artrip.domain.home.response;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -11,6 +12,7 @@
@Setter
@Builder
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class HomeListResponse {

private Long exhibit_id;
Expand All @@ -20,5 +22,8 @@ public class HomeListResponse {
private String exhibitPeriod;

private String hallName;
private String countryName;
private String regionName;

}

Loading
Loading