Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 방 참여, 나가기 기능 구현 #28

Merged
merged 32 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
034ee6e
feat: Room, Participant, Routine, Certification 엔티티 생성
ymkim97 Oct 30, 2023
bb3add1
feat: Room 엔티티 인증 시간 검증 로직 추가
ymkim97 Oct 30, 2023
ece1678
test: Room 엔티티 테스트 코드 작성
ymkim97 Oct 30, 2023
b067abb
refactor: Room 관련 엔티티 수정
ymkim97 Oct 31, 2023
00558f6
feat: 방 생성 기능 구현
ymkim97 Oct 31, 2023
20cc332
chore: DynamicQuery Jacoco 예외 추가
ymkim97 Oct 31, 2023
25d0044
test: 방 생성 테스트 코드 작성
ymkim97 Oct 31, 2023
2dd7c1a
feat: 방 수정 기능 구현
ymkim97 Oct 31, 2023
7b8ff99
test: 방 수정 통합 테스트 작성
ymkim97 Oct 31, 2023
86b2b53
Merge branch 'develop' into feature/#6
ymkim97 Oct 31, 2023
051d56e
refactor: Member 관련 파일 이동
ymkim97 Oct 31, 2023
a35ce88
refactor: checkStyle에 맞춰서 변경
ymkim97 Oct 31, 2023
c299ac3
test: 추가 테스트 코드 작성
ymkim97 Oct 31, 2023
334cd6f
chore: Apache Commons Lang 의존성 추가
ymkim97 Oct 31, 2023
c0be2c9
feat: 방 참여 기능 구현
ymkim97 Oct 31, 2023
ebb5132
test: 방 참여 기능 테스트 작성
ymkim97 Oct 31, 2023
8b08467
Merge branch 'develop' into feature/#16
ymkim97 Nov 1, 2023
77f51ad
Merge branch 'develop' into feature/#16
ymkim97 Nov 2, 2023
3b71611
feat: 방 나가기 기능 구현
ymkim97 Nov 2, 2023
4df9541
chore: test yml JPA 로그 추가
ymkim97 Nov 2, 2023
f3cc036
test: 방 참여, 나가기 일부 테스트 작성
ymkim97 Nov 2, 2023
0753648
feat: 방 나가기 구현 마무리
ymkim97 Nov 2, 2023
0db0a20
fix: Morning -> Night 수정
ymkim97 Nov 2, 2023
d256953
test: 방 나가기 추가 테스트 코드 작성
ymkim97 Nov 2, 2023
7ce8ccc
test: 방 나가기 추가 테스트 작성
ymkim97 Nov 3, 2023
b40b601
feat: 방 ID로 존재 확인 로직 추가
ymkim97 Nov 3, 2023
d8a66df
Merge remote-tracking branch 'origin/feature/#16' into feature/#16
ymkim97 Nov 3, 2023
3c280c9
refactor: 오타 수정
ymkim97 Nov 3, 2023
a24e88f
Merge branch 'develop' into feature/#16
ymkim97 Nov 3, 2023
28288e9
fix: 테스트 실행 불가 해결
ymkim97 Nov 3, 2023
a27c9eb
fix: CI 오류 해결
ymkim97 Nov 3, 2023
92c512d
refactor: 코드 리뷰 반영
ymkim97 Nov 3, 2023
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
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ dependencies {

// Configuration Binding
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"

// Apache Commons Lang 3
implementation 'org.apache.commons:commons-lang3:3.13.0'

// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
Expand Down
117 changes: 113 additions & 4 deletions src/main/java/com/moabam/api/application/RoomService.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
package com.moabam.api.application;

import static com.moabam.api.domain.entity.enums.RoomType.*;
import static com.moabam.global.error.model.ErrorMessage.*;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.moabam.api.domain.entity.Member;
import com.moabam.api.domain.entity.Participant;
import com.moabam.api.domain.entity.Room;
import com.moabam.api.domain.entity.Routine;
import com.moabam.api.domain.entity.enums.RoomType;
import com.moabam.api.domain.repository.ParticipantRepository;
import com.moabam.api.domain.repository.ParticipantSearchRepository;
import com.moabam.api.domain.repository.RoomRepository;
import com.moabam.api.domain.repository.RoutineRepository;
import com.moabam.api.dto.CreateRoomRequest;
import com.moabam.api.dto.EnterRoomRequest;
import com.moabam.api.dto.ModifyRoomRequest;
import com.moabam.api.dto.RoomMapper;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.exception.ForbiddenException;
import com.moabam.global.error.exception.NotFoundException;

Expand All @@ -31,6 +37,7 @@ public class RoomService {
private final RoutineRepository routineRepository;
private final ParticipantRepository participantRepository;
private final ParticipantSearchRepository participantSearchRepository;
private final MemberService memberService;

@Transactional
public void createRoom(Long memberId, CreateRoomRequest createRoomRequest) {
Expand All @@ -40,6 +47,7 @@ public void createRoom(Long memberId, CreateRoomRequest createRoomRequest) {
.room(room)
.memberId(memberId)
.build();

participant.enableManager();
roomRepository.save(room);
routineRepository.saveAll(routines);
Expand All @@ -48,18 +56,119 @@ public void createRoom(Long memberId, CreateRoomRequest createRoomRequest) {

@Transactional
public void modifyRoom(Long memberId, Long roomId, ModifyRoomRequest modifyRoomRequest) {
// TODO: 추후에 별도 메서드로 뺄듯
Participant participant = participantSearchRepository.findParticipant(roomId, memberId)
.orElseThrow(() -> new NotFoundException(PARTICIPANT_NOT_FOUND));
Participant participant = getParticipant(memberId, roomId);

if (!participant.isManager()) {
throw new ForbiddenException(ROOM_MODIFY_UNAUTHORIZED_REQUEST);
}

Room room = roomRepository.findById(roomId).orElseThrow(() -> new NotFoundException(ROOM_NOT_FOUND));
Room room = getRoom(roomId);
room.changeTitle(modifyRoomRequest.title());
room.changePassword(modifyRoomRequest.password());
room.changeCertifyTime(modifyRoomRequest.certifyTime());
room.changeMaxCount(modifyRoomRequest.maxUserCount());
}

@Transactional
public void enterRoom(Long memberId, Long roomId, EnterRoomRequest enterRoomRequest) {
Room room = getRoom(roomId);
validateRoomEnter(memberId, enterRoomRequest.password(), room);

room.increaseCurrentUserCount();
increaseRoomCount(memberId, room.getRoomType());

Participant participant = Participant.builder()
.room(room)
.memberId(memberId)
.build();
participantRepository.save(participant);
}

@Transactional
public void exitRoom(Long memberId, Long roomId) {
Participant participant = getParticipant(memberId, roomId);
Room room = participant.getRoom();

if (participant.isManager() && room.getCurrentUserCount() != 1) {
throw new BadRequestException(ROOM_EXIT_MANAGER_FAIL);
}

decreaseRoomCount(memberId, room.getRoomType());
participant.removeRoom();
participantRepository.flush();
participantRepository.delete(participant);

if (!participant.isManager()) {
room.decreaseCurrentUserCount();
return;
}

roomRepository.flush();
roomRepository.delete(room);
}

public void validateRoomById(Long roomId) {
if (!roomRepository.existsById(roomId)) {
throw new NotFoundException(ROOM_NOT_FOUND);
}
}

private Participant getParticipant(Long memberId, Long roomId) {
return participantSearchRepository.findParticipant(memberId, roomId)
.orElseThrow(() -> new NotFoundException(PARTICIPANT_NOT_FOUND));
}

private Room getRoom(Long roomId) {
return roomRepository.findById(roomId).orElseThrow(() -> new NotFoundException(ROOM_NOT_FOUND));
}

private void validateRoomEnter(Long memberId, String requestPassword, Room room) {
if (!isEnterRoomAvailable(memberId, room.getRoomType())) {
throw new BadRequestException(MEMBER_ROOM_EXCEED);
}

if (!StringUtils.isEmpty(requestPassword) && !room.getPassword().equals(requestPassword)) {
throw new BadRequestException(WRONG_ROOM_PASSWORD);
}

if (room.getCurrentUserCount() == room.getMaxUserCount()) {
throw new BadRequestException(ROOM_MAX_USER_REACHED);
}
}

private boolean isEnterRoomAvailable(Long memberId, RoomType roomType) {
Member member = memberService.getById(memberId);

if (roomType.equals(MORNING) && member.getCurrentMorningCount() >= 3) {
return false;
}

if (roomType.equals(NIGHT) && member.getCurrentNightCount() >= 3) {
return false;
}

return true;
}

private void increaseRoomCount(Long memberId, RoomType roomType) {
Member member = memberService.getById(memberId);

if (roomType.equals(MORNING)) {
member.enterMorningRoom();
return;
}

member.enterNightRoom();
}

private void decreaseRoomCount(Long memberId, RoomType roomType) {
Member member = memberService.getById(memberId);

if (roomType.equals(MORNING)) {
member.exitMorningRoom();
return;
}

member.exitNightRoom();
}
}
4 changes: 2 additions & 2 deletions src/main/java/com/moabam/api/domain/entity/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
@Getter
@Table(name = "member")
@SQLDelete(sql = "UPDATE member SET deleted_at = CURRENT_TIMESTAMP where id = ?")
@Where(clause = "deleted_at IS NOT NULL")
@Where(clause = "deleted_at IS NULL")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity {

Expand Down Expand Up @@ -103,7 +103,7 @@ public void exitMorningRoom() {
}

public void exitNightRoom() {
if (currentMorningCount > 0) {
if (currentNightCount > 0) {
currentNightCount--;
}
}
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/moabam/api/domain/entity/Participant.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class Participant {
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "room_id", updatable = false, nullable = false)
@JoinColumn(name = "room_id", updatable = false)
private Room room;

@Column(name = "member_id", updatable = false, nullable = false)
Expand All @@ -48,6 +48,9 @@ public class Participant {
@Column(name = "deleted_at")
private LocalDateTime deletedAt;

@Column(name = "deleted_room_title", length = 30)
private String deletedRoomTitle;

@Builder
private Participant(Long id, Room room, Long memberId) {
this.id = id;
Expand All @@ -68,4 +71,9 @@ public void enableManager() {
public void updateCertifyCount() {
this.certifyCount += 1;
}

public void removeRoom() {
this.deletedRoomTitle = this.room.getTitle();
this.room = null;
}
Comment on lines +75 to +78
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고냥 저는 Room도 soft delete 하는게 낫지 않을까 개인적인 생각 ㅋ.ㅋ

}
14 changes: 12 additions & 2 deletions src/main/java/com/moabam/api/domain/entity/Room.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public class Room extends BaseTimeEntity {
@Column(name = "id")
private Long id;

// TODO: 한글 10자도 맞나?
@Column(name = "title", nullable = false, length = 30)
private String title;

Expand All @@ -66,7 +65,6 @@ public class Room extends BaseTimeEntity {
@Column(name = "max_user_count", nullable = false)
private int maxUserCount;

// TODO: 한글 길이 고려
@Column(name = "announcement", length = 255)
private String announcement;

Expand Down Expand Up @@ -111,6 +109,18 @@ public void changeMaxCount(int maxUserCount) {
this.maxUserCount = maxUserCount;
}

public void increaseCurrentUserCount() {
this.currentUserCount += 1;

if (this.currentUserCount > this.maxUserCount) {
throw new BadRequestException(ROOM_MAX_USER_REACHED);
}
}

public void decreaseCurrentUserCount() {
this.currentUserCount -= 1;
}

public void upgradeRoomImage(String roomImage) {
this.roomImage = roomImage;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class ParticipantSearchRepository {

private final JPAQueryFactory jpaQueryFactory;

public Optional<Participant> findParticipant(Long roomId, Long memberId) {
public Optional<Participant> findParticipant(Long memberId, Long roomId) {
return Optional.ofNullable(
jpaQueryFactory.selectFrom(participant)
.where(
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/moabam/api/dto/EnterRoomRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.moabam.api.dto;

import jakarta.validation.constraints.Pattern;

public record EnterRoomRequest(
@Pattern(regexp = "^(|[0-9]{4,8})$") String password
) {

}
14 changes: 14 additions & 0 deletions src/main/java/com/moabam/api/presentation/RoomController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.moabam.api.presentation;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
Expand All @@ -11,6 +12,7 @@

import com.moabam.api.application.RoomService;
import com.moabam.api.dto.CreateRoomRequest;
import com.moabam.api.dto.EnterRoomRequest;
import com.moabam.api.dto.ModifyRoomRequest;

import jakarta.validation.Valid;
Expand All @@ -35,4 +37,16 @@ public void modifyRoom(@Valid @RequestBody ModifyRoomRequest modifyRoomRequest,
@PathVariable("roomId") Long roomId) {
roomService.modifyRoom(1L, roomId, modifyRoomRequest);
}

@PostMapping("/{roomId}")
@ResponseStatus(HttpStatus.OK)
public void enterRoom(@Valid @RequestBody EnterRoomRequest enterRoomRequest, @PathVariable("roomId") Long roomId) {
roomService.enterRoom(1L, roomId, enterRoomRequest);
}

@DeleteMapping("/{roomId}")
@ResponseStatus(HttpStatus.OK)
public void exitRoom(@PathVariable("roomId") Long roomId) {
roomService.exitRoom(1L, roomId);
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/moabam/global/error/model/ErrorMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ public enum ErrorMessage {
ROOM_NOT_FOUND("존재하지 않는 방 입니다."),
ROOM_MAX_USER_COUNT_MODIFY_FAIL("잘못된 최대 인원수 설정입니다."),
ROOM_MODIFY_UNAUTHORIZED_REQUEST("방장이 아닌 사용자는 방을 수정할 수 없습니다."),
ROOM_EXIT_MANAGER_FAIL("인원수가 2명 이상일 때는 방장을 위임해야 합니다."),
PARTICIPANT_NOT_FOUND("방에 대한 참여자의 정보가 없습니다."),
WRONG_ROOM_PASSWORD("방의 비밀번호가 일치하지 않습니다."),
ROOM_MAX_USER_REACHED("방의 인원수가 찼습니다."),

LOGIN_FAILED("로그인에 실패했습니다."),
REQUEST_FAILED("네트워크 접근 실패입니다."),
GRANT_FAILED("인가 코드 실패"),
MEMBER_NOT_FOUND("존재하지 않는 회원입니다."),
MEMBER_ROOM_EXCEED("참여할 수 있는 방의 개수가 모두 찼습니다."),

INVALID_BUG_COUNT("벌레 개수는 0 이상이어야 합니다."),
INVALID_PRICE("가격은 0 이상이어야 합니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;

import com.fasterxml.jackson.databind.ObjectMapper;
Expand All @@ -24,7 +23,6 @@

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class BugControllerTest {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
package com.moabam.api.presentation;

import static com.moabam.global.common.util.OAuthParameterNames.CLIENT_ID;
import static com.moabam.global.common.util.OAuthParameterNames.CLIENT_SECRET;
import static com.moabam.global.common.util.OAuthParameterNames.CODE;
import static com.moabam.global.common.util.OAuthParameterNames.GRANT_TYPE;
import static com.moabam.global.common.util.OAuthParameterNames.REDIRECT_URI;
import static com.moabam.global.common.util.OAuthParameterNames.RESPONSE_TYPE;
import static com.moabam.global.common.util.OAuthParameterNames.SCOPE;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static com.moabam.global.common.util.OAuthParameterNames.*;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -23,7 +15,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.test.web.client.match.MockRestRequestMatchers;
Expand All @@ -44,7 +35,6 @@

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class MemberControllerTest {

@Autowired
Expand Down
Loading