Skip to content

Commit

Permalink
feat: 방 생성, 수정 기능 구현 (#20)
Browse files Browse the repository at this point in the history
* feat: Room, Participant, Routine, Certification 엔티티 생성

* feat: Room 엔티티 인증 시간 검증 로직 추가

* test: Room 엔티티 테스트 코드 작성

* refactor: Room 관련 엔티티 수정

* feat: 방 생성 기능 구현

* chore: DynamicQuery Jacoco 예외 추가

* test: 방 생성 테스트 코드 작성

* feat: 방 수정 기능 구현

* test: 방 수정 통합 테스트 작성

* refactor: Member 관련 파일 이동

* refactor: checkStyle에 맞춰서 변경

* test: 추가 테스트 코드 작성

* refactor: 코드 리뷰 반영

* refactor: 불필요한 메서드 삭제
  • Loading branch information
ymkim97 authored Nov 1, 2023
1 parent 136beea commit ec1bc6d
Show file tree
Hide file tree
Showing 28 changed files with 1,084 additions and 20 deletions.
28 changes: 15 additions & 13 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,19 @@ jacocoTestReport {

afterEvaluate {
classDirectories.setFrom(
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
"**/*Application*",
"**/*Config*",
"**/*Request*",
"**/*Response*",
"**/*Exception*",
"**/*Mapper*",
"**/*ErrorMessage*",
] + Qdomains)
})
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
"**/*Application*",
"**/*Config*",
"**/*Request*",
"**/*Response*",
"**/*Exception*",
"**/*Mapper*",
"**/*ErrorMessage*",
"**/*DynamicQuery*",
"**/*BaseTimeEntity*",
] + Qdomains)
})
)
}
}
Expand Down Expand Up @@ -115,8 +117,8 @@ sonar {
property "sonar.host.url", "https://sonarcloud.io"
property 'sonar.coverage.jacoco.xmlReportPaths', 'build/reports/jacoco/test/jacocoTestReport.xml'
property 'sonar.coverage.exclusions', '**/test/**, **/Q*.java, **/*Doc*.java, **/resources/** ' +
',**/*Application*.java , **/*Config*.java, **/*Request*.java, **/*Response*.java ,**/*Exception*.java ' +
',**/*ErrorMessage*.java, **/*Mapper*.java'
',**/*Application*.java , **/*Config*.java, **/*Request*.java, **/*Response*.java ,**/*Exception*.java ' +
',**/*ErrorMessage*.java, **/*Mapper*.java'
property 'sonar.java.checkstyle.reportPaths', 'build/reports/checkstyle/main.xml'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.springframework.web.util.UriComponentsBuilder;

import com.moabam.api.dto.AuthorizationCodeRequest;
import com.moabam.api.mapper.OAuthMapper;
import com.moabam.api.dto.OAuthMapper;
import com.moabam.global.common.util.GlobalConstant;
import com.moabam.global.config.OAuthConfig;
import com.moabam.global.error.exception.BadRequestException;
Expand Down
65 changes: 65 additions & 0 deletions src/main/java/com/moabam/api/application/RoomService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.moabam.api.application;

import static com.moabam.global.error.model.ErrorMessage.*;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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.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.ModifyRoomRequest;
import com.moabam.api.dto.RoomMapper;
import com.moabam.global.error.exception.ForbiddenException;
import com.moabam.global.error.exception.NotFoundException;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class RoomService {

private final RoomRepository roomRepository;
private final RoutineRepository routineRepository;
private final ParticipantRepository participantRepository;
private final ParticipantSearchRepository participantSearchRepository;

@Transactional
public void createRoom(Long memberId, CreateRoomRequest createRoomRequest) {
Room room = RoomMapper.toRoomEntity(createRoomRequest);
List<Routine> routines = RoomMapper.toRoutineEntity(room, createRoomRequest.routines());
Participant participant = Participant.builder()
.room(room)
.memberId(memberId)
.build();
participant.enableManager();
roomRepository.save(room);
routineRepository.saveAll(routines);
participantRepository.save(participant);
}

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

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

Room room = roomRepository.findById(roomId).orElseThrow(() -> new NotFoundException(ROOM_NOT_FOUND));
room.changeTitle(modifyRoomRequest.title());
room.changePassword(modifyRoomRequest.password());
room.changeCertifyTime(modifyRoomRequest.certifyTime());
room.changeMaxCount(modifyRoomRequest.maxUserCount());
}
}
53 changes: 53 additions & 0 deletions src/main/java/com/moabam/api/domain/entity/Certification.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.moabam.api.domain.entity;

import static java.util.Objects.*;

import com.moabam.global.common.entity.BaseTimeEntity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@Table(name = "certification")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Certification extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "routine_id", nullable = false, updatable = false)
private Routine routine;

@Column(name = "member_id", nullable = false, updatable = false)
private Long memberId;

@Column(name = "image", nullable = false)
private String image;

@Builder
private Certification(Long id, Routine routine, Long memberId, String image) {
this.id = id;
this.routine = requireNonNull(routine);
this.memberId = requireNonNull(memberId);
this.image = requireNonNull(image);
}

public void changeImage(String image) {
this.image = image;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.moabam.api.domain;
package com.moabam.api.domain.entity;

import static java.util.Objects.*;

Expand All @@ -8,6 +8,7 @@
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

import com.moabam.api.domain.entity.enums.Role;
import com.moabam.global.common.entity.BaseTimeEntity;
import com.moabam.global.common.util.BaseImageUrl;

Expand Down
71 changes: 71 additions & 0 deletions src/main/java/com/moabam/api/domain/entity/Participant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.moabam.api.domain.entity;

import static java.util.Objects.*;

import java.time.LocalDateTime;

import org.hibernate.annotations.SQLDelete;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@Table(name = "participant")
@SQLDelete(sql = "UPDATE participant SET deleted_at = CURRENT_TIMESTAMP where id = ?")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Participant {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

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

@Column(name = "member_id", updatable = false, nullable = false)
private Long memberId;

@Column(name = "is_manager")
private boolean isManager;

@Column(name = "certify_count")
private int certifyCount;

@Column(name = "deleted_at")
private LocalDateTime deletedAt;

@Builder
private Participant(Long id, Room room, Long memberId) {
this.id = id;
this.room = requireNonNull(room);
this.memberId = requireNonNull(memberId);
this.isManager = false;
this.certifyCount = 0;
}

public void disableManager() {
this.isManager = false;
}

public void enableManager() {
this.isManager = true;
}

public void updateCertifyCount() {
this.certifyCount += 1;
}
}
134 changes: 134 additions & 0 deletions src/main/java/com/moabam/api/domain/entity/Room.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package com.moabam.api.domain.entity;

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

import org.hibernate.annotations.ColumnDefault;

import com.moabam.api.domain.entity.enums.RoomType;
import com.moabam.global.common.entity.BaseTimeEntity;
import com.moabam.global.error.exception.BadRequestException;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@Table(name = "room")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Room extends BaseTimeEntity {

private static final String ROOM_LEVEL_0_IMAGE = "'temptemp'";
private static final String ROOM_LEVEL_10_IMAGE = "'temp'";
private static final String ROOM_LEVEL_20_IMAGE = "'tempp'";
private static final int MORNING_START_TIME = 4;
private static final int MORNING_END_TIME = 10;
private static final int NIGHT_START_TIME = 20;
private static final int NIGHT_END_TIME = 2;
private static final int CLOCK_ZERO = 0;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

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

@Column(name = "password", length = 8)
private String password;

@Column(name = "level", nullable = false)
private int level;

@Enumerated(value = EnumType.STRING)
@Column(name = "room_type")
private RoomType roomType;

@Column(name = "certify_time", nullable = false)
private int certifyTime;

@Column(name = "current_user_count", nullable = false)
private int currentUserCount;

@Column(name = "max_user_count", nullable = false)
private int maxUserCount;

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

@ColumnDefault(ROOM_LEVEL_0_IMAGE)
@Column(name = "room_image", length = 500)
private String roomImage;

@Builder
private Room(Long id, String title, String password, RoomType roomType, int certifyTime, int maxUserCount) {
this.id = id;
this.title = requireNonNull(title);
this.password = password;
this.level = 0;
this.roomType = requireNonNull(roomType);
this.certifyTime = validateCertifyTime(roomType, certifyTime);
this.currentUserCount = 1;
this.maxUserCount = maxUserCount;
this.roomImage = ROOM_LEVEL_0_IMAGE;
}

public void levelUp() {
this.level += 1;
}

public void changeAnnouncement(String announcement) {
this.announcement = announcement;
}

public void changeTitle(String title) {
this.title = title;
}

public void changePassword(String password) {
this.password = password;
}

public void changeMaxCount(int maxUserCount) {
if (maxUserCount < this.currentUserCount) {
throw new BadRequestException(ROOM_MAX_USER_COUNT_MODIFY_FAIL);
}

this.maxUserCount = maxUserCount;
}

public void upgradeRoomImage(String roomImage) {
this.roomImage = roomImage;
}

public void changeCertifyTime(int certifyTime) {
this.certifyTime = validateCertifyTime(this.roomType, certifyTime);
}

private int validateCertifyTime(RoomType roomType, int certifyTime) {
if (roomType.equals(MORNING) && (certifyTime < MORNING_START_TIME || certifyTime > MORNING_END_TIME)) {
throw new BadRequestException(INVALID_REQUEST_FIELD);
}

if (roomType.equals(NIGHT)
&& ((certifyTime < NIGHT_START_TIME && certifyTime > NIGHT_END_TIME) || certifyTime < CLOCK_ZERO)) {
throw new BadRequestException(INVALID_REQUEST_FIELD);
}

return certifyTime;
}
}
Loading

0 comments on commit ec1bc6d

Please sign in to comment.