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

[BE] 미팅 생성 #102

Merged
merged 14 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package moim_today.application.meeting;

import moim_today.dto.meeting.MeetingCreateRequest;

public interface MeetingService {

void createMeeting(final MeetingCreateRequest meetingCreateRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package moim_today.application.meeting;

import moim_today.dto.meeting.MeetingCreateRequest;
import moim_today.implement.meeting.meeting.MeetingManager;
import org.springframework.stereotype.Service;

@Service
public class MeetingServiceImpl implements MeetingService {

private final MeetingManager meetingManager;

public MeetingServiceImpl(final MeetingManager meetingManager) {
this.meetingManager = meetingManager;
}

@Override
public void createMeeting(final MeetingCreateRequest meetingCreateRequest) {
meetingManager.createMeeting(meetingCreateRequest);
}
}
15 changes: 15 additions & 0 deletions backend/src/main/java/moim_today/domain/meeting/Meeting.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package moim_today.domain.meeting;

import moim_today.domain.meeting.enums.MeetingCategory;

import java.time.LocalDateTime;

public record Meeting(
long moimId,
String agenda,
LocalDateTime startDateTime,
LocalDateTime endDateTime,
String place,
MeetingCategory meetingCategory
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package moim_today.domain.meeting.enums;

public enum MeetingCategory {

SINGLE, REGULAR
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package moim_today.dto.meeting;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Builder;
import moim_today.domain.meeting.enums.MeetingCategory;
import moim_today.persistence.entity.meeting.meeting.MeetingJpaEntity;

import java.time.LocalDateTime;

@Builder
public record MeetingCreateRequest(
long moimId,
String agenda,

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
LocalDateTime startDateTime,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
LocalDateTime endDateTime,

String place,
MeetingCategory meetingCategory
) {

public MeetingJpaEntity toEntity() {
return MeetingJpaEntity.builder()
.moimId(moimId)
.agenda(agenda)
.startDateTime(startDateTime)
.endDateTime(endDateTime)
.place(place)
.build();
}

public MeetingJpaEntity toEntity(final LocalDateTime startDateTime, final LocalDateTime endDateTime) {
return MeetingJpaEntity.builder()
.moimId(moimId)
.agenda(agenda)
.startDateTime(startDateTime)
.endDateTime(endDateTime)
.place(place)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package moim_today.dto.moim.moim;

import com.querydsl.core.annotations.QueryProjection;

import java.time.LocalDate;

public record MoimDateResponse(
LocalDate startDate,
LocalDate endDate
) {

@QueryProjection
public MoimDateResponse {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public record ScheduleResponse(
long meetingId,
String scheduleName,
DayOfWeek dayOfWeek,
String colorHex,

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
LocalDateTime startDateTime,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package moim_today.global.constant.exception;

public enum MeetingExceptionConstant {

MEETING_NOT_FOUND_ERROR("미팅이 존재하지 않습니다.");

private final String message;

MeetingExceptionConstant(final String message) {
this.message = message;
}

public String message() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package moim_today.implement.meeting.joined_meeting;

import moim_today.global.annotation.Implement;
import moim_today.implement.moim.joined_moim.JoinedMoimFinder;
import moim_today.persistence.entity.meeting.joined_meeting.JoinedMeetingJpaEntity;
import moim_today.persistence.repository.meeting.joined_meeting.JoinedMeetingRepository;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Implement
public class JoinedMeetingAppender {

private final JoinedMeetingRepository joinedMeetingRepository;
private final JoinedMoimFinder joinedMoimFinder;

public JoinedMeetingAppender(final JoinedMeetingRepository joinedMeetingRepository,
final JoinedMoimFinder joinedMoimFinder) {
this.joinedMeetingRepository = joinedMeetingRepository;
this.joinedMoimFinder = joinedMoimFinder;
}

@Transactional
public void saveJoinedMeeting(final long moimId, final long meetingId) {
List<Long> memberIds = joinedMoimFinder.findAllJoinedMemberId(moimId);
List<JoinedMeetingJpaEntity> joinedMeetings = new ArrayList<>();

for (long memberId : memberIds) {
JoinedMeetingJpaEntity joinedMeeting = JoinedMeetingJpaEntity.toEntity(meetingId, memberId, true);
joinedMeetings.add(joinedMeeting);
}

joinedMeetingRepository.saveAll(joinedMeetings);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package moim_today.implement.meeting.joined_meeting;

import moim_today.global.annotation.Implement;
import moim_today.persistence.repository.meeting.joined_meeting.JoinedMeetingRepository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Implement
public class JoinedMeetingFinder {

private final JoinedMeetingRepository joinedMeetingRepository;

public JoinedMeetingFinder(final JoinedMeetingRepository joinedMeetingRepository) {
this.joinedMeetingRepository = joinedMeetingRepository;
}

@Transactional(readOnly = true)
public List<Long> findAllMemberId(final long meetingId) {
return joinedMeetingRepository.findAllMemberIdByMeetingId(meetingId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package moim_today.implement.meeting.meeting;

import moim_today.global.annotation.Implement;
import moim_today.persistence.entity.meeting.meeting.MeetingJpaEntity;
import moim_today.persistence.repository.meeting.meeting.MeetingRepository;
import org.springframework.transaction.annotation.Transactional;

@Implement
public class MeetingAppender {

private final MeetingRepository meetingRepository;

public MeetingAppender(final MeetingRepository meetingRepository) {
this.meetingRepository = meetingRepository;
}

@Transactional
public void saveMeeting(final MeetingJpaEntity meetingJpaEntity) {
meetingRepository.save(meetingJpaEntity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package moim_today.implement.meeting.meeting;

import moim_today.domain.meeting.enums.MeetingCategory;
import moim_today.dto.meeting.MeetingCreateRequest;
import moim_today.dto.moim.moim.MoimDateResponse;
import moim_today.global.annotation.Implement;
import moim_today.implement.meeting.joined_meeting.JoinedMeetingAppender;
import moim_today.implement.meeting.joined_meeting.JoinedMeetingFinder;
import moim_today.implement.moim.moim.MoimFinder;
import moim_today.implement.schedule.schedule.ScheduleAppender;
import moim_today.persistence.entity.meeting.meeting.MeetingJpaEntity;
import moim_today.persistence.entity.schedule.schedule.ScheduleJpaEntity;
import org.springframework.transaction.annotation.Transactional;

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

import static moim_today.global.constant.TimeConstant.*;


@Implement
public class MeetingManager {

private final MeetingAppender meetingAppender;
private final MoimFinder moimFinder;
private final ScheduleAppender scheduleAppender;
private final JoinedMeetingAppender joinedMeetingAppender;
private final JoinedMeetingFinder joinedMeetingFinder;

public MeetingManager(final MeetingAppender meetingAppender, final MoimFinder moimFinder,
final ScheduleAppender scheduleAppender, final JoinedMeetingAppender joinedMeetingAppender,
final JoinedMeetingFinder joinedMeetingFinder) {
this.meetingAppender = meetingAppender;
this.moimFinder = moimFinder;
this.scheduleAppender = scheduleAppender;
this.joinedMeetingAppender = joinedMeetingAppender;
this.joinedMeetingFinder = joinedMeetingFinder;
}

@Transactional
public void createMeeting(final MeetingCreateRequest meetingCreateRequest) {
MeetingCategory meetingCategory = meetingCreateRequest.meetingCategory();
String moimTitle = moimFinder.getTitleById(meetingCreateRequest.moimId());

if (meetingCategory.equals(MeetingCategory.SINGLE)) {
createSingleMeeting(meetingCreateRequest, moimTitle);

} else if (meetingCategory.equals(MeetingCategory.REGULAR)) {
createRegularMeeting(meetingCreateRequest, moimTitle);
}
}

private void createSingleMeeting(final MeetingCreateRequest meetingCreateRequest, final String moimTitle) {
MeetingJpaEntity meetingJpaEntity = meetingCreateRequest.toEntity(
meetingCreateRequest.startDateTime(),
meetingCreateRequest.endDateTime()
);

meetingAppender.saveMeeting(meetingJpaEntity);
joinedMeetingAppender.saveJoinedMeeting(meetingCreateRequest.moimId(), meetingJpaEntity.getId());
createSchedules(moimTitle, meetingJpaEntity);
}

private void createRegularMeeting(final MeetingCreateRequest meetingCreateRequest, final String moimTitle) {
MoimDateResponse moimDateResponse = moimFinder.findMoimDate(meetingCreateRequest.moimId());
LocalDate startDate = moimDateResponse.startDate();
LocalDate endDate = moimDateResponse.endDate();

LocalTime startTime = meetingCreateRequest.startDateTime().toLocalTime();
LocalTime endTime = meetingCreateRequest.endDateTime().toLocalTime();

for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusWeeks(ONE_WEEK.time())) {
LocalDateTime startDateTime = LocalDateTime.of(date, startTime);
LocalDateTime endDateTime = LocalDateTime.of(date, endTime);

MeetingJpaEntity meetingJpaEntity = meetingCreateRequest.toEntity(startDateTime, endDateTime);
meetingAppender.saveMeeting(meetingJpaEntity);
joinedMeetingAppender.saveJoinedMeeting(meetingCreateRequest.moimId(), meetingJpaEntity.getId());
createSchedules(moimTitle, meetingJpaEntity);
}
}
Comment on lines +55 to +83
Copy link
Contributor

Choose a reason for hiding this comment

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

이부분 전체 트랜잭션을 고민해봐야 할것 같습니다.
전체 트랜잭션을 안 걸게되면 롤백 시 중복 저장이 될 수 도 있을 것 같습니다.
일정 생성시 겹치는 일정이 있으면 예외를 던지지 않고 넘어가고 전체적으로 트랜잭션을 걸어야 할 것 같습니당.

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 void createSchedules(final String moimTitle, final MeetingJpaEntity meetingJpaEntity) {
List<Long> memberIds = joinedMeetingFinder.findAllMemberId(meetingJpaEntity.getId());

for (long memberId : memberIds) {
ScheduleJpaEntity scheduleJpaEntity = ScheduleJpaEntity.toEntity(memberId, moimTitle, meetingJpaEntity);
scheduleAppender.createScheduleIfNotExist(scheduleJpaEntity);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package moim_today.implement.moim.joined_moim;

import moim_today.global.annotation.Implement;
import moim_today.persistence.repository.moim.joined_moim.JoinedMoimRepository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Implement
public class JoinedMoimFinder {

private final JoinedMoimRepository joinedMoimRepository;

public JoinedMoimFinder(final JoinedMoimRepository joinedMoimRepository) {
this.joinedMoimRepository = joinedMoimRepository;
}

@Transactional(readOnly = true)
public List<Long> findAllJoinedMemberId(final long moimId) {
return joinedMoimRepository.findAllJoinedMemberId(moimId);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package moim_today.implement.moim.moim;

import moim_today.dto.moim.moim.MoimDateResponse;
import moim_today.global.annotation.Implement;
import moim_today.persistence.entity.moim.moim.MoimJpaEntity;
import moim_today.persistence.repository.moim.moim.MoimRepository;
Expand All @@ -18,4 +19,14 @@ public MoimFinder(final MoimRepository moimRepository) {
public MoimJpaEntity getById(final long moimId) {
return moimRepository.getById(moimId);
}

@Transactional(readOnly = true)
public String getTitleById(final long moimId) {
return moimRepository.getTitleById(moimId);
}

@Transactional(readOnly = true)
public MoimDateResponse findMoimDate(final long moimId) {
return moimRepository.findMoimDate(moimId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ public void createSchedule(final ScheduleJpaEntity scheduleJpaEntity) {
scheduleRepository.save(scheduleJpaEntity);
}

@Transactional
public void createScheduleIfNotExist(final ScheduleJpaEntity scheduleJpaEntity) {
if (!scheduleRepository.exists(scheduleJpaEntity)) {
scheduleRepository.save(scheduleJpaEntity);
}
}

private void validateAlreadyExist(final ScheduleJpaEntity scheduleJpaEntity) {
if (scheduleRepository.exists(scheduleJpaEntity)) {
throw new BadRequestException(SCHEDULE_ALREADY_EXIST.message());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class JoinedMeetingJpaEntity extends BaseTimeEntity {
@Association
private long memberId;

private boolean Attendance;
private boolean attendance;

protected JoinedMeetingJpaEntity() {
}
Expand All @@ -30,6 +30,15 @@ protected JoinedMeetingJpaEntity() {
private JoinedMeetingJpaEntity(final long meetingId, final long memberId, final boolean attendance) {
this.meetingId = meetingId;
this.memberId = memberId;
Attendance = attendance;
this.attendance = attendance;
}

public static JoinedMeetingJpaEntity toEntity(final long meetingId, final long memberId,
final boolean attendance) {
return JoinedMeetingJpaEntity.builder()
.meetingId(meetingId)
.memberId(memberId)
.attendance(attendance)
.build();
}
}
Loading
Loading