From 2446c4bed5953241a273ef233ff9b42b30aa1aff Mon Sep 17 00:00:00 2001 From: mikekks Date: Thu, 29 Aug 2024 19:51:50 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20Map=20=EB=B0=A9=EC=96=B4=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crew/main/entity/apply/Applies.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Applies.java b/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Applies.java index d59b6806..decbcbf6 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Applies.java +++ b/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Applies.java @@ -27,27 +27,45 @@ public Applies(List applies) { .collect(Collectors.groupingBy(Apply::getMeetingId)); } - public int getAppliedCount(Integer meetingId){ + public int getAppliedCount(Integer meetingId) { List applies = appliesMap.get(meetingId); - if(applies == null){ + if (applies == null) { return 0; } return applies.size(); } public long getApprovedCount(Integer meetingId) { + List applies = appliesMap.get(meetingId); + + if (applies == null) { + return 0; + } + return appliesMap.get(meetingId).stream() .filter(apply -> apply.getStatus().equals(EnApplyStatus.APPROVE)) .count(); } public Boolean isApply(Integer meetingId, Integer userId) { + List applies = appliesMap.get(meetingId); + + if (applies == null) { + return false; + } + return appliesMap.get(meetingId).stream() .anyMatch(apply -> apply.getUserId().equals(userId)); } public Boolean isApproved(Integer meetingId, Integer userId) { + List applies = appliesMap.get(meetingId); + + if (applies == null) { + return false; + } + return appliesMap.get(meetingId).stream() .anyMatch(apply -> apply.getUserId().equals(userId) && apply.getStatus().equals(EnApplyStatus.APPROVE)); From 03433b7d95b1691d63902743f6fc2688616d1b32 Mon Sep 17 00:00:00 2001 From: mikekks Date: Thu, 29 Aug 2024 19:53:23 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=EB=B0=B0=EB=84=88=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EC=BF=BC=EB=A6=AC=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../makers/crew/main/entity/apply/Apply.java | 182 ++++++------- .../entity/meeting/MeetingRepository.java | 7 +- .../makers/crew/main/entity/post/Post.java | 253 +++++++++--------- .../crew/main/entity/post/PostRepository.java | 25 +- .../MeetingV2GetMeetingBannerResponseDto.java | 52 ++-- ...tingV2GetMeetingBannerResponseUserDto.java | 19 +- .../meeting/v2/service/MeetingV2Service.java | 30 ++- .../v2/service/MeetingV2ServiceImpl.java | 70 +++-- 8 files changed, 341 insertions(+), 297 deletions(-) diff --git a/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Apply.java b/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Apply.java index ea4deb97..706ef03a 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Apply.java +++ b/main/src/main/java/org/sopt/makers/crew/main/entity/apply/Apply.java @@ -13,7 +13,9 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; + import java.time.LocalDateTime; + import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -36,94 +38,94 @@ @Table(name = "apply") public class Apply { - /** - * Primary Key - */ - @Id - @GeneratedValue(strategy = IDENTITY) - private Integer id; - - /** - * 지원 타입 - */ - @Column(name = "type", nullable = false, columnDefinition = "integer default 0") - @Convert(converter = ApplyTypeConverter.class) - private EnApplyType type; - - /** - * 지원한 모임 - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "meetingId", nullable = false) - private Meeting meeting; - - /** - * 지원한 모임 ID - */ - @Column(insertable = false, updatable = false) - private Integer meetingId; - - /** - * 지원자 - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userId", nullable = false) - private User user; - - /** - * 지원자 ID - */ - @Column(insertable = false, updatable = false) - private Integer userId; - - /** - * 지원 동기 - */ - @Column(name = "content", nullable = false) - private String content; - - /** - * 지원한 날짜 - */ - @Column(name = "appliedDate", nullable = false, columnDefinition = "TIMESTAMP") - @CreatedDate - private LocalDateTime appliedDate; - - /** - * 지원 상태 - */ - @Column(name = "status", nullable = false, columnDefinition = "integer default 0") - @Convert(converter = ApplyStatusConverter.class) - private EnApplyStatus status; - - @Builder - public Apply(EnApplyType type, Meeting meeting, Integer meetingId, User user, Integer userId, - String content) { - this.type = type; - this.meeting = meeting; - this.meetingId = meetingId; - this.user = user; - this.userId = userId; - this.content = content; - this.appliedDate = LocalDateTime.now(); - this.status = EnApplyStatus.WAITING; - } - - public void updateApplyStatus(EnApplyStatus status) { - this.status = status; - } - - public void validateDuplicateUpdateApplyStatus(EnApplyStatus updatedApplyStatus){ - if(updatedApplyStatus.equals(this.getStatus())){ - throw new BadRequestException(ALREADY_PROCESSED_APPLY.getErrorCode()); - } - } - - public String getContent(Integer requestUserId){ - if(!this.userId.equals(requestUserId)){ - return ""; - } - - return this.content; - } + /** + * Primary Key + */ + @Id + @GeneratedValue(strategy = IDENTITY) + private Integer id; + + /** + * 지원 타입 + */ + @Column(name = "type", nullable = false, columnDefinition = "integer default 0") + @Convert(converter = ApplyTypeConverter.class) + private EnApplyType type; + + /** + * 지원한 모임 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "meetingId", nullable = false) + private Meeting meeting; + + /** + * 지원한 모임 ID + */ + @Column(insertable = false, updatable = false) + private Integer meetingId; + + /** + * 지원자 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "userId", nullable = false) + private User user; + + /** + * 지원자 ID + */ + @Column(insertable = false, updatable = false) + private Integer userId; + + /** + * 지원 동기 + */ + @Column(name = "content", nullable = false) + private String content; + + /** + * 지원한 날짜 + */ + @Column(name = "appliedDate", nullable = false, columnDefinition = "TIMESTAMP") + @CreatedDate + private LocalDateTime appliedDate; + + /** + * 지원 상태 + */ + @Column(name = "status", nullable = false, columnDefinition = "integer default 0") + @Convert(converter = ApplyStatusConverter.class) + private EnApplyStatus status; + + @Builder + public Apply(EnApplyType type, Meeting meeting, Integer meetingId, User user, Integer userId, + String content) { + this.type = type; + this.meeting = meeting; + this.meetingId = meetingId; + this.user = user; + this.userId = userId; + this.content = content; + this.appliedDate = LocalDateTime.now(); + this.status = EnApplyStatus.WAITING; + } + + public void updateApplyStatus(EnApplyStatus status) { + this.status = status; + } + + public void validateDuplicateUpdateApplyStatus(EnApplyStatus updatedApplyStatus) { + if (updatedApplyStatus.equals(this.getStatus())) { + throw new BadRequestException(ALREADY_PROCESSED_APPLY.getErrorCode()); + } + } + + public String getContent(Integer requestUserId) { + if (!this.userId.equals(requestUserId)) { + return ""; + } + + return this.content; + } } diff --git a/main/src/main/java/org/sopt/makers/crew/main/entity/meeting/MeetingRepository.java b/main/src/main/java/org/sopt/makers/crew/main/entity/meeting/MeetingRepository.java index 776578ba..e8a70abe 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/entity/meeting/MeetingRepository.java +++ b/main/src/main/java/org/sopt/makers/crew/main/entity/meeting/MeetingRepository.java @@ -3,11 +3,11 @@ import static org.sopt.makers.crew.main.common.exception.ErrorStatus.NOT_FOUND_MEETING; import java.util.List; -import java.util.Optional; import org.sopt.makers.crew.main.common.exception.BadRequestException; import org.sopt.makers.crew.main.entity.user.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface MeetingRepository extends JpaRepository, MeetingSearchRepository { @@ -15,10 +15,11 @@ public interface MeetingRepository extends JpaRepository, Meet List findAllByUser(User user); - Optional findById(Integer meetingId); - default Meeting findByIdOrThrow(Integer meetingId) { return findById(meetingId) .orElseThrow(() -> new BadRequestException(NOT_FOUND_MEETING.getErrorCode())); } + + @Query("SELECT m FROM Meeting m JOIN FETCH m.user ORDER BY m.id DESC LIMIT 20") + List findTop20ByOrderByIdDesc(); } \ No newline at end of file diff --git a/main/src/main/java/org/sopt/makers/crew/main/entity/post/Post.java b/main/src/main/java/org/sopt/makers/crew/main/entity/post/Post.java index ee1f9c56..aa8cf1dc 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/entity/post/Post.java +++ b/main/src/main/java/org/sopt/makers/crew/main/entity/post/Post.java @@ -13,11 +13,14 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; + import java.time.LocalDateTime; + import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; + import org.hibernate.annotations.Type; import org.sopt.makers.crew.main.common.exception.ForbiddenException; import org.sopt.makers.crew.main.entity.meeting.Meeting; @@ -33,129 +36,129 @@ @Table(name = "post") public class Post { - /** - * 게시글의 고유 식별자 - */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Integer id; - - /** - * 게시글 제목 - */ - @Column(nullable = false) - private String title; - - /** - * 게시글 내용 - */ - @Column(nullable = false, columnDefinition = "TEXT") - private String contents; - - /** - * 게시글 작성일 - */ - @Column(name = "createdDate", nullable = false, columnDefinition = "TIMESTAMP") - @CreatedDate - private LocalDateTime createdDate; - - /** - * 게시글 수정일 - */ - @Column(name = "updatedDate", nullable = false, columnDefinition = "TIMESTAMP") - @LastModifiedDate - private LocalDateTime updatedDate; - - /** - * 조회수 - */ - @Column(nullable = false, columnDefinition = "int default 0") - private int viewCount; - - /** - * 이미지 리스트 - */ - @Column(name = "images", columnDefinition = "text[]") - @Type(StringArrayType.class) - private String[] images; - - /** - * 작성자 정보 - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userId", nullable = false) - private User user; - - /** - * 작성자의 고유 식별자 - */ - @Column(insertable = false, updatable = false) - private Integer userId; - - /** - * 게시글이 속한 미팅 정보 - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "meetingId", nullable = false) - private Meeting meeting; - - /** - * 게시글이 속한 미팅의 고유 식별자 - */ - @Column(insertable = false, updatable = false) - private Integer meetingId; - - /** - * 게시글에 달린 댓글 수 - */ - @Column(nullable = false, columnDefinition = "int default 0") - private int commentCount; - - /** - * 게시글에 대한 좋아요 수 - */ - @Column(nullable = false, columnDefinition = "int default 0") - private int likeCount; - - @Builder - public Post(String title, String contents, String[] images, User user, Meeting meeting) { - this.title = title; - this.contents = contents; - this.viewCount = 0; - this.images = images; - this.user = user; - this.userId = user.getId(); - this.meeting = meeting; - this.meetingId = meeting.getId(); - this.commentCount = 0; - this.likeCount = 0; - } - - public void increaseCommentCount() { - this.commentCount++; - } - - public void decreaseCommentCount() { - this.commentCount--; - } - - public void increaseLikeCount() { - this.likeCount++; - } - - public void decreaseLikeCount() { - this.likeCount--; - } - - public void isWriter(Integer userId) { - if (!this.userId.equals(userId)) { - throw new ForbiddenException(FORBIDDEN_EXCEPTION.getErrorCode()); - } - } - - public void updatePost(String title, String contents, String[] images) { - this.title = title; - this.contents = contents; - this.images = images; - } + /** + * 게시글의 고유 식별자 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + /** + * 게시글 제목 + */ + @Column(nullable = false) + private String title; + + /** + * 게시글 내용 + */ + @Column(nullable = false, columnDefinition = "TEXT") + private String contents; + + /** + * 게시글 작성일 + */ + @Column(name = "createdDate", nullable = false, columnDefinition = "TIMESTAMP") + @CreatedDate + private LocalDateTime createdDate; + + /** + * 게시글 수정일 + */ + @Column(name = "updatedDate", nullable = false, columnDefinition = "TIMESTAMP") + @LastModifiedDate + private LocalDateTime updatedDate; + + /** + * 조회수 + */ + @Column(nullable = false, columnDefinition = "int default 0") + private int viewCount; + + /** + * 이미지 리스트 + */ + @Column(name = "images", columnDefinition = "text[]") + @Type(StringArrayType.class) + private String[] images; + + /** + * 작성자 정보 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "userId", nullable = false) + private User user; + + /** + * 작성자의 고유 식별자 + */ + @Column(insertable = false, updatable = false) + private Integer userId; + + /** + * 게시글이 속한 미팅 정보 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "meetingId", nullable = false) + private Meeting meeting; + + /** + * 게시글이 속한 미팅의 고유 식별자 + */ + @Column(insertable = false, updatable = false) + private Integer meetingId; + + /** + * 게시글에 달린 댓글 수 + */ + @Column(nullable = false, columnDefinition = "int default 0") + private int commentCount; + + /** + * 게시글에 대한 좋아요 수 + */ + @Column(nullable = false, columnDefinition = "int default 0") + private int likeCount; + + @Builder + public Post(String title, String contents, String[] images, User user, Meeting meeting) { + this.title = title; + this.contents = contents; + this.viewCount = 0; + this.images = images; + this.user = user; + this.userId = user.getId(); + this.meeting = meeting; + this.meetingId = meeting.getId(); + this.commentCount = 0; + this.likeCount = 0; + } + + public void increaseCommentCount() { + this.commentCount++; + } + + public void decreaseCommentCount() { + this.commentCount--; + } + + public void increaseLikeCount() { + this.likeCount++; + } + + public void decreaseLikeCount() { + this.likeCount--; + } + + public void isWriter(Integer userId) { + if (!this.userId.equals(userId)) { + throw new ForbiddenException(FORBIDDEN_EXCEPTION.getErrorCode()); + } + } + + public void updatePost(String title, String contents, String[] images) { + this.title = title; + this.contents = contents; + this.images = images; + } } \ No newline at end of file diff --git a/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostRepository.java b/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostRepository.java index 3dccb412..71b37fc4 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostRepository.java +++ b/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostRepository.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Optional; + import org.sopt.makers.crew.main.common.exception.BadRequestException; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -12,21 +13,19 @@ public interface PostRepository extends JpaRepository, PostSearchRepository { - Optional findById(Integer postId); - - default Post findByIdOrThrow(Integer postId) { - return findById(postId) - .orElseThrow(() -> new BadRequestException(NOT_FOUND_POST.getErrorCode())); - } + default Post findByIdOrThrow(Integer postId) { + return findById(postId) + .orElseThrow(() -> new BadRequestException(NOT_FOUND_POST.getErrorCode())); + } - Optional findFirstByMeetingIdOrderByIdDesc(Integer meetingId); + Integer countByMeetingId(Integer meetingId); - Integer countByMeetingId(Integer meetingId); + List findAllByMeetingId(Integer meetingId); - List findAllByMeetingId(Integer meetingId); + List findAllByMeetingIdIn(List meetingIds); - @Modifying(clearAutomatically = true) - @Transactional - @Query("DELETE FROM Post p WHERE p.meetingId = :meetingId") - void deleteAllByMeetingIdQuery(Integer meetingId); + @Modifying(clearAutomatically = true) + @Transactional + @Query("DELETE FROM Post p WHERE p.meetingId = :meetingId") + void deleteAllByMeetingIdQuery(Integer meetingId); } diff --git a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseDto.java b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseDto.java index c543886a..51356df3 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseDto.java +++ b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseDto.java @@ -2,36 +2,36 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.Optional; +import org.sopt.makers.crew.main.entity.meeting.Meeting; import org.sopt.makers.crew.main.entity.meeting.enums.MeetingCategory; import org.sopt.makers.crew.main.entity.meeting.enums.MeetingJoinablePart; import org.sopt.makers.crew.main.entity.meeting.vo.ImageUrlVO; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.RequiredArgsConstructor; @Getter -@AllArgsConstructor(staticName = "of") +@RequiredArgsConstructor @Schema(name = "MeetingV2GetMeetingBannerResponseDto", description = "모임 배너 응답 Dto") public class MeetingV2GetMeetingBannerResponseDto { /** 모임 ID */ @Schema(description = "모임 id", example = "1") @NotNull - private Integer id; + private final Integer id; /** 유저 Crew ID */ @Schema(description = "크루에서 사용하는 userId", example = "1") @NotNull - private Integer userId; + private final Integer userId; /** 모임 제목 */ @Schema(description = "모임 제목", example = "모임 제목입니다1") @NotNull - private String title; + private final String title; /** * 모임 카테고리 @@ -40,7 +40,7 @@ public class MeetingV2GetMeetingBannerResponseDto { */ @Schema(description = "모임 카테고리", example = "스터디") @NotNull - private MeetingCategory category; + private final MeetingCategory category; /** * 썸네일 이미지 @@ -49,64 +49,76 @@ public class MeetingV2GetMeetingBannerResponseDto { */ @Schema(description = "모임 사진", example = "[url] 형식") @NotNull - private List imageURL; + private final List imageURL; /** 모임 활동 시작일 */ @Schema(description = "모임 활동 시작일", example = "2024-07-31T15:30:00") @NotNull - private LocalDateTime mStartDate; + private final LocalDateTime mStartDate; /** 모임 활동 종료일 */ @Schema(description = "모임 활동 종료일", example = "2024-08-25T15:30:00") @NotNull - private LocalDateTime mEndDate; + private final LocalDateTime mEndDate; /** 모임 모집 시작일 */ @Schema(description = "모임 모집 시작일", example = "2024-06-11T15:30:00") @NotNull - private LocalDateTime startDate; + private final LocalDateTime startDate; /** 모임 모집 종료일 */ @Schema(description = "모임 모집 종료일", example = "2024-06-17T15:30:00") @NotNull - private LocalDateTime endDate; + private final LocalDateTime endDate; /** 모임 인원 */ @Schema(description = "모집 인원", example = "20") @NotNull - private Integer capacity; + private final Integer capacity; /** 최근 활동 일자 */ @Schema(description = "최근 활동 일자", example = "2024-06-11T15:30:00") - private Optional recentActivityDate; + private final LocalDateTime recentActivityDate; /** 모임 타겟 기수 */ @Schema(description = "모임 타겟 기수", example = "33") @NotNull - private Integer targetActiveGeneration; + private final Integer targetActiveGeneration; /** 모임 타겟 파트 */ @Schema(description = "모임 타겟 파트", example = "[\"PM\", \"SERVER\"]") @NotNull - private MeetingJoinablePart[] joinableParts; + private final MeetingJoinablePart[] joinableParts; /** 지원자 수 */ @Schema(description = "지원자 수", example = "50") @NotNull - private Integer applicantCount; + private final long applicantCount; /** 가입된 지원자 수 */ @Schema(description = "가입된 지원자 수", example = "9") @NotNull - private Integer approvedUserCount; + private final long approvedUserCount; /** 개설자 정보 */ @Schema(description = "모임장 정보", example = "") @NotNull - private MeetingV2GetMeetingBannerResponseUserDto user; + private final MeetingV2GetMeetingBannerResponseUserDto user; /** 미팅 상태 */ @Schema(description = "모임 상태", example = "1") @NotNull - private Integer status; + private final Integer status; + + public static MeetingV2GetMeetingBannerResponseDto of(Meeting meeting, LocalDateTime recentActivityDate, + long applicantCount, long approvedUserCount, MeetingV2GetMeetingBannerResponseUserDto meetingCreator, LocalDateTime now) { + + return new MeetingV2GetMeetingBannerResponseDto(meeting.getId(), meeting.getUserId(), meeting.getTitle(), + meeting.getCategory(), + meeting.getImageURL(), meeting.getMStartDate(), meeting.getMEndDate(), meeting.getStartDate(), + meeting.getEndDate(), meeting.getCapacity(), recentActivityDate, meeting.getTargetActiveGeneration(), + meeting.getJoinableParts(), applicantCount, approvedUserCount, + meetingCreator, meeting.getMeetingStatus(now)); + } + } diff --git a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseUserDto.java b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseUserDto.java index c46c2ee1..608d8427 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseUserDto.java +++ b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/dto/response/MeetingV2GetMeetingBannerResponseUserDto.java @@ -1,31 +1,38 @@ package org.sopt.makers.crew.main.meeting.v2.dto.response; +import org.sopt.makers.crew.main.entity.user.User; + import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.RequiredArgsConstructor; @Getter -@AllArgsConstructor(staticName = "of") +@RequiredArgsConstructor @Schema(name = "MeetingV2GetMeetingBannerResponseUserDto", description = "모임 배너 유저 Dto") public class MeetingV2GetMeetingBannerResponseUserDto { /** 개설자 crew ID */ @Schema(description = "모임장 id, 크루에서 사용하는 userId", example = "1") @NotNull - private Integer id; + private final Integer id; /** 개설자 */ @Schema(description = "모임장 이름", example = "홍길동") @NotNull - private String name; + private final String name; /** 개설자 playground ID */ @Schema(description = "모임장 org id, 메이커스 프로덕트에서 범용적으로 사용하는 userId", example = "1") @NotNull - private Integer orgId; + private final Integer orgId; /** 프로필 사진 */ @Schema(description = "모임장 프로필 사진", example = "[url] 형식") - private String profileImage; + private final String profileImage; + + public static MeetingV2GetMeetingBannerResponseUserDto of(User meetingCreator) { + return new MeetingV2GetMeetingBannerResponseUserDto(meetingCreator.getId(), meetingCreator.getName(), + meetingCreator.getOrgId(), meetingCreator.getProfileImage()); + } } diff --git a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2Service.java b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2Service.java index d668a0b1..9d254128 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2Service.java +++ b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2Service.java @@ -1,6 +1,7 @@ package org.sopt.makers.crew.main.meeting.v2.service; import java.util.List; + import org.sopt.makers.crew.main.meeting.v2.dto.query.MeetingGetAppliesQueryDto; import org.sopt.makers.crew.main.meeting.v2.dto.query.MeetingV2GetAllMeetingByOrgUserQueryDto; import org.sopt.makers.crew.main.meeting.v2.dto.query.MeetingV2GetAllMeetingQueryDto; @@ -18,29 +19,30 @@ public interface MeetingV2Service { - MeetingV2GetAllMeetingByOrgUserDto getAllMeetingByOrgUser( - MeetingV2GetAllMeetingByOrgUserQueryDto queryDto); + MeetingV2GetAllMeetingByOrgUserDto getAllMeetingByOrgUser( + MeetingV2GetAllMeetingByOrgUserQueryDto queryDto); - List getMeetingBanner(); + List getMeetingBanner(); - MeetingV2CreateMeetingResponseDto createMeeting(MeetingV2CreateMeetingBodyDto requestBody, Integer userId); + MeetingV2CreateMeetingResponseDto createMeeting(MeetingV2CreateMeetingBodyDto requestBody, Integer userId); - MeetingV2ApplyMeetingResponseDto applyMeeting(MeetingV2ApplyMeetingDto requestBody, Integer userId); + MeetingV2ApplyMeetingResponseDto applyMeeting(MeetingV2ApplyMeetingDto requestBody, Integer userId); - void applyMeetingCancel(Integer meetingId, Integer userId); + void applyMeetingCancel(Integer meetingId, Integer userId); - MeetingGetApplyListResponseDto findApplyList(MeetingGetAppliesQueryDto queryCommand, Integer meetingId, - Integer userId); + MeetingGetApplyListResponseDto findApplyList(MeetingGetAppliesQueryDto queryCommand, Integer meetingId, + Integer userId); - MeetingV2GetAllMeetingDto getMeetings(MeetingV2GetAllMeetingQueryDto queryCommand); + MeetingV2GetAllMeetingDto getMeetings(MeetingV2GetAllMeetingQueryDto queryCommand); - void deleteMeeting(Integer meetingId, Integer userId); + void deleteMeeting(Integer meetingId, Integer userId); - void updateMeeting(Integer meetingId, MeetingV2CreateMeetingBodyDto requestBody, Integer userId); + void updateMeeting(Integer meetingId, MeetingV2CreateMeetingBodyDto requestBody, Integer userId); - void updateApplyStatus(Integer meetingId, ApplyV2UpdateStatusBodyDto requestBody, Integer userId); + void updateApplyStatus(Integer meetingId, ApplyV2UpdateStatusBodyDto requestBody, Integer userId); - AppliesCsvFileUrlResponseDto getAppliesCsvFileUrl(Integer meetingId, List status, String order, Integer userId); + AppliesCsvFileUrlResponseDto getAppliesCsvFileUrl(Integer meetingId, List status, String order, + Integer userId); - MeetingV2GetMeetingByIdResponseDto getMeetingById(Integer meetingId, Integer userId); + MeetingV2GetMeetingByIdResponseDto getMeetingById(Integer meetingId, Integer userId); } diff --git a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2ServiceImpl.java b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2ServiceImpl.java index 97becf4d..8204dcb8 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2ServiceImpl.java +++ b/main/src/main/java/org/sopt/makers/crew/main/meeting/v2/service/MeetingV2ServiceImpl.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; @@ -78,7 +79,7 @@ @Transactional(readOnly = true) public class MeetingV2ServiceImpl implements MeetingV2Service { - private final static int ZERO = 0; + private static final int ZERO = 0; private final UserRepository userRepository; private final ApplyRepository applyRepository; @@ -128,33 +129,50 @@ public MeetingV2GetAllMeetingByOrgUserDto getAllMeetingByOrgUser( return MeetingV2GetAllMeetingByOrgUserDto.of(pagedUserJoinedList, pageMetaDto); } + /** + * @Note: 최근 활동 여부는 게시글 생성일자를 기준으로 진행한다. + * */ @Override public List getMeetingBanner() { - return meetingRepository.findAll() + + List meetings = meetingRepository.findTop20ByOrderByIdDesc(); + List meetingIds = meetings.stream().map(Meeting::getId).toList(); + + List posts = postRepository.findAllByMeetingIdIn(meetingIds); + List filterLatestPosts = filterLatestPostsByMeetingId(posts); + Map postMap = filterLatestPosts.stream() + .collect(Collectors.toMap(post -> post.getMeeting().getId(), post -> post)); + + Applies applies = new Applies(applyRepository.findAllByMeetingIdIn(meetingIds)); + + return getResponseDto(meetings, postMap, applies); + } + + + private List filterLatestPostsByMeetingId(List posts) { + return posts.stream() + .collect(Collectors.groupingBy(Post::getMeetingId, + Collectors.maxBy(Comparator.comparing(Post::getCreatedDate)))) + .values() .stream() - .sorted(Comparator.comparing(Meeting::getId).reversed()) - .limit(20) + .flatMap(Optional::stream) + .collect(Collectors.toList()); + } + + private List getResponseDto(List meetings, + Map postMap, Applies applies) { + return meetings.stream() .map(meeting -> { - Optional recentPost = postRepository.findFirstByMeetingIdOrderByIdDesc(meeting.getId()); - Optional recentActivityDate = recentPost.map(Post::getCreatedDate); - - List applies = applyRepository.findAllByMeetingId(meeting.getId()); - Integer applicantCount = applies.size(); - Integer appliedUserCount = applies.stream() - .filter(apply -> apply.getStatus().equals(EnApplyStatus.APPROVE)).toList().size(); - - User meetingLeader = userRepository.findByIdOrThrow(meeting.getUserId()); - MeetingV2GetMeetingBannerResponseUserDto meetingLeaderDto = MeetingV2GetMeetingBannerResponseUserDto - .of(meetingLeader.getId(), meetingLeader.getName(), meetingLeader.getOrgId(), - meetingLeader.getProfileImage()); - - return MeetingV2GetMeetingBannerResponseDto.of(meeting.getId(), meeting.getUserId(), - meeting.getTitle(), meeting.getCategory(), meeting.getImageURL(), - meeting.getMStartDate(), meeting.getMEndDate(), meeting.getStartDate(), - meeting.getEndDate(), - meeting.getCapacity(), recentActivityDate, meeting.getTargetActiveGeneration(), - meeting.getJoinableParts(), applicantCount, appliedUserCount, meetingLeaderDto, - meeting.getMeetingStatus(time.now())); + MeetingV2GetMeetingBannerResponseUserDto meetingCreatorDto = MeetingV2GetMeetingBannerResponseUserDto.of(meeting.getUser()); + + LocalDateTime recentActivityDate = null; + if (postMap.containsKey(meeting.getId())) { + recentActivityDate = postMap.get(meeting.getId()).getCreatedDate(); + } + + return MeetingV2GetMeetingBannerResponseDto.of(meeting, recentActivityDate, + applies.getAppliedCount(meeting.getId()), applies.getApprovedCount(meeting.getId()), + meetingCreatorDto, time.now()); }).toList(); } @@ -332,7 +350,8 @@ public MeetingV2GetMeetingByIdResponseDto getMeetingById(Integer meetingId, Inte Meeting meeting = meetingRepository.findByIdOrThrow(meetingId); User meetingCreator = userRepository.findByIdOrThrow(meeting.getUserId()); - Applies applies = new Applies(applyRepository.findAllByMeetingIdWithUser(meetingId, List.of(WAITING, APPROVE, REJECT), ORDER_ASC)); + Applies applies = new Applies( + applyRepository.findAllByMeetingIdWithUser(meetingId, List.of(WAITING, APPROVE, REJECT), ORDER_ASC)); Boolean isHost = meeting.checkMeetingLeader(user.getId()); Boolean isApply = applies.isApply(meetingId, user.getId()); @@ -343,7 +362,6 @@ public MeetingV2GetMeetingByIdResponseDto getMeetingById(Integer meetingId, Inte .map(apply -> ApplyWholeInfoDto.of(apply, apply.getUser(), userId)) .toList(); - return MeetingV2GetMeetingByIdResponseDto.of(meeting, approvedCount, isHost, isApply, isApproved, meetingCreator, applyWholeInfoDtos, time.now()); }