Skip to content

Commit

Permalink
feat: 공동 모임장 추가 구현 (#463)
Browse files Browse the repository at this point in the history
* add: BaseTimeEntity 추가

* feat: 공동모임장인 모임도 조회할 수 있도록 구현

* fix: co_leader로 수정

* test: test data 추가

* refactor: 내가 신청한 모임 정렬 조건 추가

* test: Mock 테스트 삭제 - 이제 해당 케이스들이 통합테스트로 커버됨.

* test: 내가 만든 모임 조회, 내가 신청한 모임 조회 테스트 코드 작성

* refactor:
1. 모임장, 공동모임장의 경우 검증 로직 추가
2. LocalDateTime.now 부분 수정

* feat: 모임장, 공동모임장의 경우 검증 로직 구현

* test:
1. 모임장, 공동 모임장인 경우 모임 신청 테스트 코드 작성
2. 시간 수정으로 인한 일부 테스트 코드 수정

* test: 시간 수정으로 인한 일부 테스트 코드 수정

* fix: clearAutomatically = true 추가

* fix: User -> userId 변경

* test: '모임 수정', '모임 삭제', '모임 지원자 상태 변경'에 공동모임장 관련 테스트 코드 작성

* test: 테스트 시퀀스 및 데이터 일부 수정
  • Loading branch information
mikekks authored Oct 16, 2024
1 parent 01dbc3a commit 3d5c260
Show file tree
Hide file tree
Showing 18 changed files with 650 additions and 402 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,47 @@

public interface ApplyRepository extends JpaRepository<Apply, Integer>, ApplySearchRepository {

@Query("select a from Apply a join fetch a.meeting m where a.userId = :userId and a.status = :statusValue")
List<Apply> findAllByUserIdAndStatus(@Param("userId") Integer userId,
@Param("statusValue") EnApplyStatus statusValue);

@Query("select a from Apply a join fetch a.meeting m join fetch m.user u where a.userId = :userId")
List<Apply> findAllByUserId(@Param("userId") Integer userId);

@Query("select a "
+ "from Apply a "
+ "join fetch a.user u "
+ "where a.meetingId = :meetingId "
+ "and a.status in :statuses order by :order")
List<Apply> findAllByMeetingIdWithUser(@Param("meetingId") Integer meetingId, @Param("statuses") List<EnApplyStatus> statuses, @Param("order") String order);

List<Apply> findAllByMeetingIdAndStatus(Integer meetingId, EnApplyStatus statusValue);

List<Apply> findAllByMeetingId(Integer meetingId);

List<Apply> findAllByMeetingIdIn(List<Integer> meetingIds);

boolean existsByMeetingIdAndUserId(Integer meetingId, Integer userId);

@Transactional
@Modifying
@Query("delete from Apply a where a.meeting.id = :meetingId and a.userId = :userId")
void deleteByMeetingIdAndUserId(@Param("meetingId") Integer meetingId, @Param("userId") Integer userId);

default Apply findByIdOrThrow(Integer applyId) {
return findById(applyId)
.orElseThrow(() -> new BadRequestException(NOT_FOUND_APPLY.getErrorCode()));
}

@Modifying(clearAutomatically = true)
@Transactional
@Query("DELETE FROM Apply a WHERE a.meetingId = :meetingId")
void deleteAllByMeetingIdQuery(Integer meetingId);
@Query("select a from Apply a join fetch a.meeting m where a.userId = :userId and a.status = :statusValue")
List<Apply> findAllByUserIdAndStatus(@Param("userId") Integer userId,
@Param("statusValue") EnApplyStatus statusValue);

@Query("select a "
+ "from Apply a "
+ "join fetch a.meeting m "
+ "join fetch m.user u "
+ "where a.userId = :userId "
+ "ORDER BY a.id DESC ")
List<Apply> findAllByUserIdOrderByIdDesc(@Param("userId") Integer userId);

@Query("select a "
+ "from Apply a "
+ "join fetch a.user u "
+ "where a.meetingId = :meetingId "
+ "and a.status in :statuses order by :order")
List<Apply> findAllByMeetingIdWithUser(@Param("meetingId") Integer meetingId,
@Param("statuses") List<EnApplyStatus> statuses, @Param("order") String order);

List<Apply> findAllByMeetingIdAndStatus(Integer meetingId, EnApplyStatus statusValue);

List<Apply> findAllByMeetingId(Integer meetingId);

List<Apply> findAllByMeetingIdIn(List<Integer> meetingIds);

boolean existsByMeetingIdAndUserId(Integer meetingId, Integer userId);

@Transactional
@Modifying(clearAutomatically = true)
@Query("delete from Apply a where a.meeting.id = :meetingId and a.userId = :userId")
void deleteByMeetingIdAndUserId(@Param("meetingId") Integer meetingId, @Param("userId") Integer userId);

default Apply findByIdOrThrow(Integer applyId) {
return findById(applyId)
.orElseThrow(() -> new BadRequestException(NOT_FOUND_APPLY.getErrorCode()));
}

@Modifying(clearAutomatically = true)
@Transactional
@Query("DELETE FROM Apply a WHERE a.meetingId = :meetingId")
void deleteAllByMeetingIdQuery(Integer meetingId);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.sopt.makers.crew.main.entity.meeting;

import org.sopt.makers.crew.main.entity.common.BaseTimeEntity;
import org.sopt.makers.crew.main.entity.user.User;

import jakarta.persistence.Entity;
Expand All @@ -20,7 +21,7 @@
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "co_leader")
public class CoLeader {
public class CoLeader extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import org.sopt.makers.crew.main.entity.user.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CoLeaderRepository extends JpaRepository<CoLeader, Integer> {
Expand All @@ -12,4 +13,6 @@ public interface CoLeaderRepository extends JpaRepository<CoLeader, Integer> {

List<CoLeader> findAllByMeetingIdIn(List<Integer> meetingId);

List<CoLeader> findAllByUserId(Integer userId);

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package org.sopt.makers.crew.main.entity.meeting;

import static org.sopt.makers.crew.main.global.exception.ErrorStatus.*;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.sopt.makers.crew.main.global.exception.BadRequestException;

public class CoLeaders {
/**
* Key : MeetingId
* Value : 해당 모임의 공동 모임장 목록
*
* @implNote : List 내에 있는 CoLeader 객체는 fetch join 으로 다른 객체를 불러오지 않은 상태
* @implNote : 해당 자료형을 사용할 때는 'hasCoLeader' 메서드 사용 적극 권장
* @implNote : 해당 자료형을 사용할 때는 'isCoLeaderPresent' 메서드 사용 적극 권장
*
* */
private final Map<Integer, List<CoLeader>> coLeadersMap;
Expand All @@ -21,6 +25,12 @@ public CoLeaders(List<CoLeader> coLeaders) {
.collect(Collectors.groupingBy(coLeader -> coLeader.getMeeting().getId()));
}

public void validateCoLeader(Integer meetingId, Integer requestUserId) {
if (isCoLeader(meetingId, requestUserId)) {
throw new BadRequestException(CO_LEADER_CANNOT_APPLY.getErrorCode());
}
}

public boolean isCoLeader(Integer meetingId, Integer requestUserId) {
if (!isCoLeaderPresent(meetingId)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,12 @@ public void validateMeetingCreator(Integer requestUserId) {
}
}

public void validateIsNotMeetingLeader(Integer requestUserId) {
if (checkMeetingLeader(requestUserId)) {
throw new BadRequestException(LEADER_CANNOT_APPLY.getErrorCode());
}
}

public Boolean checkMeetingLeader(Integer userId) {
return this.userId.equals(userId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@
import java.util.List;

import org.sopt.makers.crew.main.global.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<Meeting, Integer>, MeetingSearchRepository {

List<Meeting> findAllByUserId(Integer userId);

List<Meeting> findAllByUser(User user);
/**
* @implSpec : 특정 유저가 모임장이거나 공동모임장인 모임을 최근에 만들어진 순으로 조회한다.
* **/
@Query("SELECT m "
+ "FROM Meeting m "
+ "JOIN fetch m.user "
+ "WHERE m.user.id =:userId "
+ "OR m.id IN (:coLeaderMeetingIds)"
+ "ORDER BY m.id DESC ")
List<Meeting> findAllByUserIdOrIdInWithUser(Integer userId, List<Integer> coLeaderMeetingIds);

default Meeting findByIdOrThrow(Integer meetingId) {
return findById(meetingId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public enum ErrorStatus {
NOT_FOUND_APPLY("신청상태가 아닌 모임입니다."),
ALREADY_PROCESSED_APPLY("이미 해당 상태로 처리된 신청 정보입니다."),
MAX_IMAGE_UPLOAD_EXCEEDED("이미지는 최대 10개까지만 업로드 가능합니다."),
LEADER_CANNOT_APPLY("모임장은 신청할 수 없습니다."),
CO_LEADER_CANNOT_APPLY("공동 모임장은 신청할 수 없습니다."),

/**
* 401 UNAUTHORIZED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ public MeetingV2CreateMeetingResponseDto createMeeting(MeetingV2CreateMeetingBod
public MeetingV2ApplyMeetingResponseDto applyMeeting(MeetingV2ApplyMeetingDto requestBody, Integer userId) {
Meeting meeting = meetingRepository.findByIdOrThrow(requestBody.getMeetingId());
User user = userRepository.findByIdOrThrow(userId);
CoLeaders coLeaders = new CoLeaders(coLeaderRepository.findAllByMeetingId(meeting.getId()));

List<Apply> applies = applyRepository.findAllByMeetingId(meeting.getId());

Expand All @@ -226,9 +227,10 @@ public MeetingV2ApplyMeetingResponseDto applyMeeting(MeetingV2ApplyMeetingDto re
validateApplyPeriod(meeting);
validateUserActivities(user);
validateUserJoinableParts(user, meeting);
coLeaders.validateCoLeader(meeting.getId(), user.getId());
meeting.validateIsNotMeetingLeader(userId);

Apply apply = applyMapper.toApplyEntity(requestBody, EnApplyType.APPLY, meeting, user,
userId);
Apply apply = applyMapper.toApplyEntity(requestBody, EnApplyType.APPLY, meeting, user, userId);
Apply savedApply = applyRepository.save(apply);
return MeetingV2ApplyMeetingResponseDto.of(savedApply.getId());
}
Expand Down Expand Up @@ -449,7 +451,7 @@ private String createCsvFile(List<Apply> applies) {
}

private Boolean checkActivityStatus(Meeting meeting) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime now = time.now();
LocalDateTime mStartDate = meeting.getMStartDate();
LocalDateTime mEndDate = meeting.getMEndDate();
return now.isEqual(mStartDate) || (now.isAfter(mStartDate) && now.isBefore(mEndDate));
Expand Down Expand Up @@ -494,7 +496,7 @@ private void validateUserAlreadyApplied(Integer userId, List<Apply> applies) {
}

private void validateApplyPeriod(Meeting meeting) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime now = time.now();
if (now.isAfter(meeting.getEndDate()) || now.isBefore(meeting.getStartDate())) {
throw new BadRequestException(NOT_IN_APPLY_PERIOD.getErrorCode());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ public record MeetingV2GetCreatedMeetingByUserResponseDto(
@NotNull
int appliedCount
) {
public static MeetingV2GetCreatedMeetingByUserResponseDto of(Meeting meeting, boolean isCoLeader, User meetingCreator, int appliedCount,
public static MeetingV2GetCreatedMeetingByUserResponseDto of(Meeting meeting, boolean isCoLeader, int appliedCount,
LocalDateTime now) {
MeetingCreatorDto creatorDto = MeetingCreatorDto.of(meetingCreator);
MeetingCreatorDto creatorDto = MeetingCreatorDto.of(meeting.getUser());
boolean canJoinOnlyActiveGeneration = meeting.getTargetActiveGeneration() == CrewConst.ACTIVE_GENERATION
&& meeting.getCanJoinOnlyActiveGeneration();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.sopt.makers.crew.main.entity.meeting.CoLeader;
import org.sopt.makers.crew.main.entity.meeting.CoLeaderRepository;
import org.sopt.makers.crew.main.entity.meeting.CoLeaders;
import org.sopt.makers.crew.main.global.exception.BaseException;
Expand Down Expand Up @@ -94,34 +95,43 @@ public UserV2GetUserOwnProfileResponseDto getUserOwnProfile(Integer userId) {
return UserV2GetUserOwnProfileResponseDto.of(user);
}

/**
* @implSpec : 유저가 모임장이거나 공동모임장인 모임을 모두 조회한다.
* @implNote : my 의미 == 내가 모임장이거나 공동모임장인 경우
*
* **/
@Override
public UserV2GetCreatedMeetingByUserResponseDto getCreatedMeetingByUser(Integer userId) {
User meetingCreator = userRepository.findByIdOrThrow(userId);
List<Integer> coLeaderMeetingIds = getCoLeaderMeetingIds(coLeaderRepository.findAllByUserId(userId));

List<Meeting> meetings = meetingRepository.findAllByUser(meetingCreator);
List<Integer> meetingIds = meetings.stream().map(Meeting::getId).toList();
Applies applies = new Applies(applyRepository.findAllByMeetingIdIn(meetingIds));
CoLeaders coLeaders = new CoLeaders(coLeaderRepository.findAllByMeetingIdIn(meetingIds));
List<Meeting> myMeetings = meetingRepository.findAllByUserIdOrIdInWithUser(userId, coLeaderMeetingIds);
List<Integer> myMeetingIds = myMeetings.stream().map(Meeting::getId).toList();
Applies applies = new Applies(applyRepository.findAllByMeetingIdIn(myMeetingIds));
CoLeaders coLeaders = new CoLeaders(coLeaderRepository.findAllByMeetingIdIn(myMeetingIds));

List<MeetingV2GetCreatedMeetingByUserResponseDto> meetingByUserDtos = meetings.stream()
List<MeetingV2GetCreatedMeetingByUserResponseDto> meetingByUserDtos = myMeetings.stream()
.map(meeting -> MeetingV2GetCreatedMeetingByUserResponseDto.of(meeting,
coLeaders.isCoLeader(meeting.getId(), userId), meetingCreator,
applies.getApprovedCount(meeting.getId()), time.now()))
coLeaders.isCoLeader(meeting.getId(), userId), applies.getApprovedCount(meeting.getId()), time.now()))
.toList();

return UserV2GetCreatedMeetingByUserResponseDto.of(meetingByUserDtos);
}

private List<Integer> getCoLeaderMeetingIds(List<CoLeader> coLeaders) {
return coLeaders.stream()
.map(coLeader -> coLeader.getMeeting().getId()).toList();
}

@Override
public UserV2GetAppliedMeetingByUserResponseDto getAppliedMeetingByUser(Integer userId) {
List<Apply> myApplies = applyRepository.findAllByUserId(userId);
List<Apply> myApplies = applyRepository.findAllByUserIdOrderByIdDesc(userId);
List<Integer> meetingIds = myApplies.stream().map(Apply::getMeetingId).toList();

Applies allApplies = new Applies(applyRepository.findAllByMeetingIdIn(meetingIds));

List<ApplyV2GetAppliedMeetingByUserResponseDto> appliedMeetingByUserDtos = myApplies.stream()
.map(apply -> ApplyV2GetAppliedMeetingByUserResponseDto.of(apply.getId(), apply.getStatus().getValue(),
MeetingV2GetCreatedMeetingByUserResponseDto.of(apply.getMeeting(), false, apply.getMeeting().getUser(),
MeetingV2GetCreatedMeetingByUserResponseDto.of(apply.getMeeting(), false,
allApplies.getApprovedCount(apply.getMeetingId()), time.now())))
.toList();

Expand Down
6 changes: 4 additions & 2 deletions main/src/main/resources/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ drop table if exists "notice" cascade;
drop table if exists "post" cascade;
drop table if exists "report" cascade;
drop table if exists "user" cascade;
drop table if exists "joint_leader" cascade;
drop table if exists "co_leader" cascade;

DROP TYPE IF EXISTS meeting_joinableparts_enum;

Expand Down Expand Up @@ -72,7 +72,9 @@ create table if not exists co_leader
"userId" integer not null
constraint fk_user
references "user"
on delete cascade
on delete cascade,
"createdTimestamp" timestamp default CURRENT_TIMESTAMP not null,
"modifiedTimestamp" timestamp default CURRENT_TIMESTAMP not null
);

create table if not exists apply
Expand Down
Loading

0 comments on commit 3d5c260

Please sign in to comment.