Skip to content

Commit

Permalink
feat: 룸 수정 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
youngsu5582 committed Oct 14, 2024
1 parent 85b9f11 commit adb297b
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 69 deletions.
1 change: 1 addition & 0 deletions backend/src/main/java/corea/exception/ExceptionType.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum ExceptionType {
ALREADY_APPLY(HttpStatus.BAD_REQUEST, "해당 방에 이미 참여했습니다."),
NOT_ALREADY_APPLY(HttpStatus.BAD_REQUEST, "아직 참여하지 않은 방입니다."),
ROOM_STATUS_INVALID(HttpStatus.BAD_REQUEST, "방이 마감되었습니다."),
MEMBER_IS_NOT_MANAGER(HttpStatus.BAD_REQUEST, "매니저가 아닙니다."),
ROOM_PARTICIPANT_EXCEED(HttpStatus.BAD_REQUEST, "방 참여 인원 수가 최대입니다."),
PARTICIPANT_SIZE_LACK(HttpStatus.BAD_REQUEST, "참여 인원이 부족하여 매칭을 진행할 수 없습니다."),
PARTICIPANT_SIZE_LACK_DUE_TO_PULL_REQUEST(HttpStatus.BAD_REQUEST, "pull request 미제출로 인해 인원이 부족하여 매칭을 진행할 수 없습니다."),
Expand Down
61 changes: 8 additions & 53 deletions backend/src/main/java/corea/room/controller/RoomController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,8 @@
import corea.auth.annotation.AccessedMember;
import corea.auth.annotation.LoginMember;
import corea.auth.domain.AuthInfo;
import corea.matchresult.dto.MatchResultResponses;
import corea.matchresult.service.MatchResultService;
import corea.room.domain.RoomStatus;
import corea.room.dto.RoomCreateRequest;
import corea.room.dto.RoomParticipantResponses;
import corea.room.dto.RoomResponse;
import corea.room.dto.RoomResponses;
import corea.room.dto.*;
import corea.room.service.RoomService;
import corea.scheduler.service.AutomaticMatchingService;
import corea.scheduler.service.AutomaticUpdateService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -25,16 +17,18 @@
public class RoomController implements RoomControllerSpecification {

private final RoomService roomService;
private final MatchResultService matchResultService;
private final AutomaticUpdateService automaticUpdateService;
private final AutomaticMatchingService automaticMatchingService;

@PostMapping
public ResponseEntity<RoomResponse> create(@LoginMember AuthInfo authInfo, @RequestBody RoomCreateRequest request) {
RoomResponse response = roomService.create(authInfo.getId(), request);

automaticMatchingService.matchOnRecruitmentDeadline(response);
automaticUpdateService.updateAtReviewDeadline(response);
return ResponseEntity.created(URI.create(String.format("/rooms/%d", response.id())))
.body(response);
}

@PutMapping
public ResponseEntity<RoomResponse> update(@LoginMember AuthInfo authInfo, @RequestBody RoomUpdateRequest request) {
RoomResponse response = roomService.update(authInfo.getId(), request);

return ResponseEntity.created(URI.create(String.format("/rooms/%d", response.id())))
.body(response);
Expand All @@ -52,55 +46,16 @@ public ResponseEntity<RoomParticipantResponses> participants(@PathVariable long
return ResponseEntity.ok(response);
}

@GetMapping("/{id}/reviewers")
public ResponseEntity<MatchResultResponses> reviewers(@PathVariable long id, @LoginMember AuthInfo authInfo) {
MatchResultResponses response = matchResultService.findReviewers(authInfo.getId(), id);
return ResponseEntity.ok(response);
}

@GetMapping("/{id}/reviewees")
public ResponseEntity<MatchResultResponses> reviewees(@PathVariable long id, @LoginMember AuthInfo authInfo) {
MatchResultResponses response = matchResultService.findReviewees(authInfo.getId(), id);
return ResponseEntity.ok(response);
}

@GetMapping("/participated")
public ResponseEntity<RoomResponses> participatedRooms(@LoginMember AuthInfo authInfo) {
RoomResponses response = roomService.findParticipatedRooms(authInfo.getId());
return ResponseEntity.ok(response);
}

@GetMapping("/opened")
public ResponseEntity<RoomResponses> openedRooms(@AccessedMember AuthInfo authInfo,
@RequestParam(defaultValue = "0") int page,
@RequestParam(value = "classification", defaultValue = "all") String expression) {
RoomResponses response = roomService.findRoomsWithRoomStatus(authInfo.getId(), page, expression, RoomStatus.OPEN);
return ResponseEntity.ok(response);
}

@GetMapping("/progress")
public ResponseEntity<RoomResponses> progressRooms(@AccessedMember AuthInfo authInfo,
@RequestParam(defaultValue = "0") int page,
@RequestParam(value = "classification", defaultValue = "all") String expression) {
RoomResponses response = roomService.findRoomsWithRoomStatus(authInfo.getId(), page, expression, RoomStatus.PROGRESS);
return ResponseEntity.ok(response);
}

@GetMapping("/closed")
public ResponseEntity<RoomResponses> closedRooms(@AccessedMember AuthInfo authInfo,
@RequestParam(defaultValue = "0") int page,
@RequestParam(value = "classification", defaultValue = "all") String expression) {
RoomResponses response = roomService.findRoomsWithRoomStatus(authInfo.getId(), page, expression, RoomStatus.CLOSE);
return ResponseEntity.ok(response);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable long id, @LoginMember AuthInfo authInfo) {
roomService.delete(id, authInfo.getId());

automaticMatchingService.cancel(id);
automaticUpdateService.cancel(id);

return ResponseEntity.noContent()
.build();
}
Expand Down
76 changes: 76 additions & 0 deletions backend/src/main/java/corea/room/dto/RoomUpdateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package corea.room.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import corea.member.domain.Member;
import corea.room.domain.Room;
import corea.room.domain.RoomClassification;
import corea.room.domain.RoomStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import java.time.LocalDateTime;
import java.util.List;

@Schema(description = "방 수정 요청")
public record RoomUpdateRequest(
@Schema(description = "방 ID", example = "99")
@NotBlank
long roomId,

@Schema(description = "방 제목", example = "MVC를 아시나요?")
@NotBlank
String title,

@Schema(description = "방 내용", example = "MVC 패턴을 아시나요?")
String content,

@Schema(description = "repository 링크", example = "https://github.com/example/java-racingcar")
@NotBlank
String repositoryLink,

@Schema(description = "썸네일 링크", example = "https://gongu.copyright.or.kr/gongu/wrt/cmmn/wrtFileImageView.do?wrtSn=13301655&filePath=L2Rpc2sxL25ld2RhdGEvMjAyMS8yMS9DTFMxMDAwNC8xMzMwMTY1NV9XUlRfMjFfQ0xTMTAwMDRfMjAyMTEyMTNfMQ==&thumbAt=Y&thumbSe=b_tbumb&wrtTy=10004")
String thumbnailLink,

@Schema(description = "상호 리뷰 인원", example = "2")
@NotNull
int matchingSize,

@Schema(description = "중심으로 리뷰하면 좋은 키워드", example = "[\"TDD\", \"클린코드\"]")
List<String> keywords,

@Schema(description = "제한 참여 인원", example = "200")
@NotNull
int limitedParticipants,

@Schema(description = "모집 마감일", example = "2024-07-30 15:00")
@NotNull
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
LocalDateTime recruitmentDeadline,

@Schema(description = "리뷰 마감일", example = "2024-08-10 23:59")
@NotNull
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
LocalDateTime reviewDeadline,

@Schema(description = "방이 속하는 분야", example = "BE")
@NotNull
RoomClassification classification
) {

private static final int INITIAL_PARTICIPANTS_SIZE = 1;
private static final RoomStatus INITIAL_ROOM_STATUS = RoomStatus.OPEN;

public Room toEntity(Member manager) {
return new Room(
roomId,
title, content,
matchingSize, repositoryLink,
thumbnailLink, keywords,
INITIAL_PARTICIPANTS_SIZE, limitedParticipants,
manager, recruitmentDeadline,
reviewDeadline, classification,
INITIAL_ROOM_STATUS
);
}
}
17 changes: 17 additions & 0 deletions backend/src/main/java/corea/room/service/RoomService.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ public RoomResponse create(long memberId, RoomCreateRequest request) {
return RoomResponse.of(room, participation.getMemberRole(), ParticipationStatus.MANAGER);
}

@Transactional
public RoomResponse update(long memberId, RoomUpdateRequest request) {
Room room = getRoom(request.roomId());
if (room.isNotMatchingManager(memberId)) {
throw new CoreaException(ExceptionType.MEMBER_IS_NOT_MANAGER);
}
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new CoreaException(ExceptionType.MEMBER_NOT_FOUND));

Room updateRoom = roomRepository.save(request.toEntity(member));
Participation participation = participationRepository.findByRoomIdAndMemberId(updateRoom.getId(), memberId)
.orElseThrow(() -> new CoreaException(ExceptionType.NOT_ALREADY_APPLY));

roomAutomaticService.updateTime(updateRoom);
return RoomResponse.of(updateRoom, participation.getMemberRole(), ParticipationStatus.MANAGER);
}

private void validateDeadLine(LocalDateTime recruitmentDeadline, LocalDateTime reviewDeadline) {
LocalDateTime currentDateTime = LocalDateTime.now();

Expand Down
16 changes: 16 additions & 0 deletions backend/src/test/java/corea/fixture/RoomFixture.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ public static Room ROOM_DOMAIN(Long id, Member member) {
RoomStatus.OPEN
);
}
public static RoomUpdateRequest ROOM_UPDATE_REQUEST(long roomId){
return new RoomUpdateRequest(
roomId,
"Test Room",
"Test Content",
"https://github.com/youngsu5582/github-api-test",
"https://gongu.copyright.or.kr/gongu/wrt/cmmn/wrtFileImageView.do?wrtSn=13301655&filePath=L2Rpc2sxL25ld2RhdGEvMjAyMS8yMS9DTFMxMDAwNC8xMzMwMTY1NV9XUlRfMjFfQ0xTMTAwMDRfMjAyMTEyMTNfMQ==&thumbAt=Y&thumbSe=b_tbumb&wrtTy=10004",
2,
List.of("TDD, 클린코드, 자바"),
10,
LocalDateTime.now(),
LocalDateTime.now()
.plusDays(14),
RoomClassification.BACKEND
);
}

public static RoomCreateRequest ROOM_CREATE_REQUEST() {
return ROOM_CREATE_REQUEST(LocalDateTime.now()
Expand Down
61 changes: 45 additions & 16 deletions backend/src/test/java/corea/room/service/RoomServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package corea.room.service;

import config.ServiceTest;
import corea.auth.domain.AuthInfo;
import corea.exception.CoreaException;
import corea.exception.ExceptionType;
import corea.fixture.MatchResultFixture;
Expand All @@ -17,7 +16,6 @@
import corea.participation.domain.ParticipationStatus;
import corea.participation.repository.ParticipationRepository;
import corea.room.domain.Room;
import corea.room.domain.RoomStatus;
import corea.room.dto.RoomCreateRequest;
import corea.room.dto.RoomParticipantResponses;
import corea.room.dto.RoomResponse;
Expand All @@ -28,9 +26,6 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -74,13 +69,32 @@ void create() {
assertThat(roomRepository.findAll()).hasSize(1);
}

@Test
@DisplayName("방의 매니저가 아니면 수정 시, 예외를 발생합니다.")
void throw_exception_when_update_with_not_manager() {
Member manager = memberRepository.save(MemberFixture.MEMBER_ROOM_MANAGER_JOYSON());
RoomResponse response = roomService.create(manager.getId(), RoomFixture.ROOM_CREATE_REQUEST());
assertThatThrownBy(() -> roomService.update(-1, RoomFixture.ROOM_UPDATE_REQUEST(response.id())))
.isInstanceOf(CoreaException.class);
}

@Test
@DisplayName("존재하지 않는 방이면, 예외를 발생합니다.")
void throw_exception_when_update_with_not_exist_room() {
Member manager = memberRepository.save(MemberFixture.MEMBER_ROOM_MANAGER_JOYSON());
roomService.create(manager.getId(), RoomFixture.ROOM_CREATE_REQUEST());
assertThatThrownBy(() -> roomService.update(manager.getId(), RoomFixture.ROOM_UPDATE_REQUEST(-1)))
.isInstanceOf(CoreaException.class);
}

@Disabled
@Test
@DisplayName("방을 생성할 때 모집 마감 시간은 현재 시간보다 1시간 이후가 아니라면 예외가 발생한다.")
void invalidRecruitmentDeadline() {
Member manager = memberRepository.save(MemberFixture.MEMBER_ROOM_MANAGER_JOYSON());

RoomCreateRequest request = RoomFixture.ROOM_CREATE_REQUEST_WITH_RECRUITMENT_DEADLINE(LocalDateTime.now().plusMinutes(59));
RoomCreateRequest request = RoomFixture.ROOM_CREATE_REQUEST_WITH_RECRUITMENT_DEADLINE(LocalDateTime.now()
.plusMinutes(59));

assertThatThrownBy(() -> roomService.create(manager.getId(), request))
.asInstanceOf(InstanceOfAssertFactories.type(CoreaException.class))
Expand All @@ -94,7 +108,9 @@ void invalidRecruitmentDeadline() {
void invalidReviewDeadline() {
Member manager = memberRepository.save(MemberFixture.MEMBER_ROOM_MANAGER_JOYSON());

RoomCreateRequest request = RoomFixture.ROOM_CREATE_REQUEST(LocalDateTime.now().plusHours(2), LocalDateTime.now().plusDays(1));
RoomCreateRequest request = RoomFixture.ROOM_CREATE_REQUEST(LocalDateTime.now()
.plusHours(2), LocalDateTime.now()
.plusDays(1));

assertThatThrownBy(() -> roomService.create(manager.getId(), request))
.asInstanceOf(InstanceOfAssertFactories.type(CoreaException.class))
Expand Down Expand Up @@ -161,8 +177,10 @@ void findParticipatedRooms() {
Member pororo = memberRepository.save(MemberFixture.MEMBER_PORORO());
Member ash = memberRepository.save(MemberFixture.MEMBER_ASH());

Room pororoRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(pororo, LocalDateTime.now().plusDays(2)));
Room ashRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(ash, LocalDateTime.now().plusDays(3)));
Room pororoRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(pororo, LocalDateTime.now()
.plusDays(2)));
Room ashRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(ash, LocalDateTime.now()
.plusDays(3)));

Member joyson = memberRepository.save(MemberFixture.MEMBER_YOUNGSU());
Long joysonId = joyson.getId();
Expand All @@ -182,8 +200,10 @@ void findNonClosedParticipatedRooms() {
Member ash = memberRepository.save(MemberFixture.MEMBER_ASH());
Member movin = memberRepository.save(MemberFixture.MEMBER_MOVIN());

Room pororoRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(pororo, LocalDateTime.now().plusDays(2)));
Room ashRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(ash, LocalDateTime.now().plusDays(3)));
Room pororoRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(pororo, LocalDateTime.now()
.plusDays(2)));
Room ashRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN(ash, LocalDateTime.now()
.plusDays(3)));
Room movinRoom = roomRepository.save(RoomFixture.ROOM_DOMAIN_WITH_CLOSED(movin));

Member joyson = memberRepository.save(MemberFixture.MEMBER_YOUNGSU());
Expand Down Expand Up @@ -259,7 +279,8 @@ void create_participationStatus_manager() {
assertAll(
() -> assertThat(response.manager()).isEqualTo(manager.getName()),
() -> assertThat(participation.isPresent()).isTrue(),
() -> assertThat(participation.get().getStatus()).isEqualTo(ParticipationStatus.MANAGER)
() -> assertThat(participation.get()
.getStatus()).isEqualTo(ParticipationStatus.MANAGER)
);
}

Expand Down Expand Up @@ -301,9 +322,13 @@ void findParticipants() {
List<Member> members = memberRepository.saveAll(MemberFixture.SEVEN_MEMBERS());

participationRepository.save(new Participation(room, manager));
participationRepository.saveAll(members.stream().map(member -> new Participation(room, member, MemberRole.BOTH, 2)).toList());
participationRepository.saveAll(members.stream()
.map(member -> new Participation(room, member, MemberRole.BOTH, 2))
.toList());

matchResultRepository.saveAll(members.stream().map(member -> MatchResultFixture.MATCH_RESULT_DOMAIN(room.getId(), manager, member)).toList());
matchResultRepository.saveAll(members.stream()
.map(member -> MatchResultFixture.MATCH_RESULT_DOMAIN(room.getId(), manager, member))
.toList());
matchResultRepository.save(MatchResultFixture.MATCH_RESULT_DOMAIN(room.getId(), members.get(0), manager));

RoomParticipantResponses participants = roomService.findParticipants(room.getId(), manager.getId());
Expand All @@ -326,9 +351,13 @@ void findParticipants_withNoPullRequestParticipants() {

List<Member> members = memberRepository.saveAll(MemberFixture.SEVEN_MEMBERS());

participationRepository.saveAll(members.stream().map(member -> new Participation(room, member, MemberRole.BOTH, 2)).toList());
participationRepository.saveAll(members.stream()
.map(member -> new Participation(room, member, MemberRole.BOTH, 2))
.toList());

matchResultRepository.saveAll(members.stream().map(member -> MatchResultFixture.MATCH_RESULT_DOMAIN(room.getId(), manager, member)).toList());
matchResultRepository.saveAll(members.stream()
.map(member -> MatchResultFixture.MATCH_RESULT_DOMAIN(room.getId(), manager, member))
.toList());
matchResultRepository.save(MatchResultFixture.MATCH_RESULT_DOMAIN(room.getId(), members.get(0), manager));


Expand Down

0 comments on commit adb297b

Please sign in to comment.