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: 방 생성, 수정 기능 구현 #20

Merged
merged 15 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
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
64 changes: 64 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,64 @@
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.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;

@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();

Copy link
Member

Choose a reason for hiding this comment

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

C: 저희 컨벤션은 return을 제외한 모두 붙여쓰는 것으로 알고 있습니다!

roomRepository.save(room);
routineRepository.saveAll(routines);
participantRepository.save(participant);
}

@Transactional
public void modifyRoom(Long memberId, Long roomId, ModifyRoomRequest modifyRoomRequest) {
// TODO: 추후에 별도 메서드로 뺄듯
Participant participant = participantRepository.findParticipantByRoomIdAndMemberId(roomId, memberId)
Copy link
Member

Choose a reason for hiding this comment

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

Q: 추후에 �별도 메서드로 뺀다는 것이 JPA를 사용안하고 직접 쿼리를 짜는 걸로 이해하면 될까요?! 아니라면, 조회에 대한 쿼리는 되도록 JPA를 안쓰고 네이티브 쿼리나 QueryDSL 사용을 권장합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

아 저건 나중에 반복적으로 쓰이면 private으로 뺄수도 있다고 일단 남겼습니다!
조회에 대한 쿼리는 JPA를 안쓰고 다른걸 권장하는 이유가 무엇인가요??

.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());
Comment on lines +60 to +63
Copy link
Member

Choose a reason for hiding this comment

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

A: 저도 항상 이게 고민인데, 하나의 메서드에서 여러 파라미터를 받아 해결할 지? 아니면 재윤, 영명님이 하신 것처럼 분리할 지? 고민입니다! 분리한 이유가 있다면 무엇인가요?

Copy link
Member Author

Choose a reason for hiding this comment

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

엔티티까지 들어가지 않고 여기서 어떤 정보들이 변하는지 확인이 가능해서 분리해보았습니다!
또한 @transactional이 붙었고 해당 메서드에서 변경감지가 일어난다는 것이 보여서 이게 더 자연스러운가?라는 고민도 있었습니다.
하지만 그냥 표현 차이라 어떻게 해도 괜찮겠네요!

}
}
52 changes: 52 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,52 @@
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(Routine routine, Long memberId, String image) {
Copy link
Contributor

Choose a reason for hiding this comment

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

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
70 changes: 70 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,70 @@
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 participants SET deleted_at = CURRENT_TIMESTAMP where id = ?")
Copy link
Contributor

Choose a reason for hiding this comment

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

participants -> participant 아닌가요?

Copy link
Member Author

Choose a reason for hiding this comment

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

헉 큰일날뻔 감사합니다 >.<

@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(Room room, Long memberId) {
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'";

Copy link
Member

Choose a reason for hiding this comment

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

C: 저희 컨벤션은 모두 붙이는 걸로 알고 있습니다!

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;
Comment on lines +46 to +48
Copy link
Member

Choose a reason for hiding this comment

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

Q: 저도 궁금하네요! 공유 부탁드립니다! ㅋㄱㅋㄱ

Copy link
Contributor

Choose a reason for hiding this comment

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

문자수 관련인가요? 저번에 찾아봤을 때 mysql이 버전이 업데이트 되면서 문자수 를 계산하는 것으로 알고있는데, 애매하네요

Copy link
Member Author

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋ 일단은 영어는 1바이트, 한글은 3바이트라 30으로 설정해두었슴다


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

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

@Enumerated(value = EnumType.STRING)
@Column(name = "type")
private RoomType roomType;
Copy link
Member

Choose a reason for hiding this comment

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

Q: 컬럼명과 필드명을 다르게 한 이유가 있을까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

헉 실수


@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(String title, String password, RoomType roomType, int certifyTime, int maxUserCount) {
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