From abe2fd9da57c2782257b38de63fa2cb4a4cc761f Mon Sep 17 00:00:00 2001 From: SHEOMM Date: Wed, 3 Apr 2024 19:42:22 +0900 Subject: [PATCH 01/19] =?UTF-8?q?feat:=20develop=20=ED=99=98=EA=B2=BD=20ht?= =?UTF-8?q?tps=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 49dac81..ffe5625 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -21,7 +21,7 @@ spring: cors: - allowed-origins: http://dev.areyouhere.today, http://dev.www.areyouhere.today + allowed-origins: https://dev.areyouhere.today, https://dev.www.areyouhere.today cookie: encode: ${SECRET_KEY} From f1620e55a1e2695925dfa4246e0c87fcc2717b29 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Wed, 3 Apr 2024 20:42:51 +0900 Subject: [PATCH 02/19] =?UTF-8?q?Feat/Attendee=20=EC=B0=B8=EA=B0=80?= =?UTF-8?q?=EC=9E=90=20=EB=B3=80=EA=B2=BD=EC=97=90=EC=84=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD=EB=8F=84=20=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20(#39)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yaml | 3 -- .../command/AttendeeCommandServiceImpl.java | 33 +++++++++++++++---- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4d03792..ae982e3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,9 +4,6 @@ on: push: branches: - main - pull_request: - branches: - - main jobs: deploy: diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java index f85fd14..c042c48 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java @@ -90,6 +90,7 @@ public void deleteAll(List deleteAttendees){ private void throwIfAttendeesNameAndNoteNotUnique(List newAttendees, Long courseId) { List newAttendeeNames = getAttendeeUniqueNames(newAttendees); Map existingAttendees = getExistingAttendeesMap(courseId, newAttendeeNames); + setUpdatedNameAttendees(existingAttendees, newAttendees); checkNameSake(newAttendees, existingAttendees); } @@ -99,13 +100,27 @@ private List getAttendeeUniqueNames(List attendees) { .distinct() .collect(Collectors.toList()); } - private Map getExistingAttendeesMap(Long courseId, List attendeeNames) { return attendeeRepository.findAttendeesByCourseIdAndNameIn(courseId, attendeeNames) .stream() .collect(Collectors.toMap(Attendee::getId, Function.identity())); } + private void setUpdatedNameAttendees(Map existingAttendees, List newAttendees) { + newAttendees.forEach(attendeeInfo -> { + if (attendeeInfo.getId() != null) { + if(!existingAttendees.containsKey(attendeeInfo.getId())){ + existingAttendees.put(attendeeInfo.getId(), Attendee.builder() + .id(attendeeInfo.getId()) + .name(attendeeInfo.getName()) + .note(attendeeInfo.getNote()) + .build()); + } + } + }); + + } + private void checkNameSake(List newAttendees, Map existingAttendees) { Map> uniqueAttendees = new HashMap<>(); @@ -117,25 +132,29 @@ private void checkNameSake(List newAttendees, Map throw new IllegalArgumentException("Attendee not found"); }).update(attendeeInfo.getName(), attendeeInfo.getNote()); - } else if (!checkOneAttendeeUnique(attendeeInfo, uniqueAttendees)) { + } else if (!addUniqueNameAndNote(attendeeInfo, uniqueAttendees)) { throw new AttendeesNotUniqueException(); } }); existingAttendees.values() .stream() - .filter(attendee -> !checkOneAttendeeUnique(attendee, uniqueAttendees)) + .filter(attendee -> !addUniqueNameAndNote(attendee, uniqueAttendees)) .findAny() .ifPresent(attendee -> { throw new AttendeesNotUniqueException(); }); } - private boolean checkOneAttendeeUnique(AttendeeInfo attendeeInfo, Map> uniqueAttendees) { - return uniqueAttendees.get(attendeeInfo.getName()).add(Optional.ofNullable(attendeeInfo.getNote()).orElse("")); + private boolean addUniqueNameAndNote(AttendeeInfo attendeeInfo, Map> uniqueAttendees) { + return uniqueAttendees + .get(attendeeInfo.getName()) + .add(Optional.ofNullable(attendeeInfo.getNote()).orElse("")); } - private boolean checkOneAttendeeUnique(Attendee attendee, Map> uniqueAttendees) { - return uniqueAttendees.get(attendee.getName()).add(Optional.ofNullable(attendee.getNote()).orElse("")); + private boolean addUniqueNameAndNote(Attendee attendee, Map> uniqueAttendees) { + return uniqueAttendees + .get(attendee.getName()) + .add(Optional.ofNullable(attendee.getNote()).orElse("")); } } From 53fbdebcdfee1ed47bc41ca8e9a9eebf7ab12bf5 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Wed, 3 Apr 2024 21:48:05 +0900 Subject: [PATCH 03/19] =?UTF-8?q?Feat/Session=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=9D=BC=EA=B4=84=20=EC=88=98=EC=A0=95=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=20(#41)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/controller/SessionController.java | 8 ++++++++ .../areyouhere/session/domain/entity/Session.java | 1 + .../domain/repository/SessionRepository.java | 4 ++++ .../dto/request/UpdateSessionsRequestDto.java | 13 +++++++++++++ .../service/command/SessionCommandService.java | 3 +++ .../service/command/SessionCommandServiceImpl.java | 9 +++++++++ .../session/service/dto/UpdateSession.java | 9 +++++++++ 7 files changed, 47 insertions(+) create mode 100644 src/main/java/com/waruru/areyouhere/session/dto/request/UpdateSessionsRequestDto.java create mode 100644 src/main/java/com/waruru/areyouhere/session/service/dto/UpdateSession.java diff --git a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java index 6e01950..8f7d2a0 100644 --- a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java +++ b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java @@ -5,6 +5,7 @@ import com.waruru.areyouhere.attendee.service.query.AttendeeQueryService; import com.waruru.areyouhere.session.dto.request.CreateSessionRequestDto; import com.waruru.areyouhere.session.dto.request.DeleteSessionRequestDto; +import com.waruru.areyouhere.session.dto.request.UpdateSessionsRequestDto; import com.waruru.areyouhere.session.dto.response.SessionAttendeesResponseDto; import com.waruru.areyouhere.session.service.command.SessionCommandService; import com.waruru.areyouhere.session.service.dto.AllSessionAttendanceInfo; @@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -84,4 +86,10 @@ public ResponseEntity getSessionAbsenteeOnly(@PathV .build()); } + @PutMapping + public ResponseEntity updateAll(@RequestBody UpdateSessionsRequestDto updateSessionsRequestDto){ + sessionCommandService.updateAll(updateSessionsRequestDto.getSessions()); + return ResponseEntity.ok().build(); + } + } diff --git a/src/main/java/com/waruru/areyouhere/session/domain/entity/Session.java b/src/main/java/com/waruru/areyouhere/session/domain/entity/Session.java index 35f3aa9..2a8f781 100644 --- a/src/main/java/com/waruru/areyouhere/session/domain/entity/Session.java +++ b/src/main/java/com/waruru/areyouhere/session/domain/entity/Session.java @@ -28,6 +28,7 @@ public class Session { @JoinColumn(name = "course_id", nullable = false) private Course course; + @Setter private String name; @Setter diff --git a/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java b/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java index ae62b7f..1832538 100644 --- a/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java +++ b/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java @@ -60,4 +60,8 @@ public interface SessionRepository extends JpaRepository{ @Query("delete from session s where s.id in :ids") public void deleteAllByIds(@Param("ids") List ids); + @Modifying(clearAutomatically = true) + @Query("UPDATE session s SET s.name= :name WHERE s.id = :sessionId") + void setSessionNameById(@Param("name") String name, @Param("sessionId") Long sessionId); + } diff --git a/src/main/java/com/waruru/areyouhere/session/dto/request/UpdateSessionsRequestDto.java b/src/main/java/com/waruru/areyouhere/session/dto/request/UpdateSessionsRequestDto.java new file mode 100644 index 0000000..c4939ee --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/session/dto/request/UpdateSessionsRequestDto.java @@ -0,0 +1,13 @@ +package com.waruru.areyouhere.session.dto.request; + +import com.waruru.areyouhere.session.service.dto.UpdateSession; +import java.util.List; +import lombok.Getter; + +@Getter +public class UpdateSessionsRequestDto { + private List sessions; +} + + + diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java index 4329340..ed56023 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java @@ -1,5 +1,6 @@ package com.waruru.areyouhere.session.service.command; +import com.waruru.areyouhere.session.service.dto.UpdateSession; import java.time.LocalDateTime; import java.util.List; @@ -8,4 +9,6 @@ public interface SessionCommandService { public void delete(List sessionIds); public void deactivate(Long sessionId); public void setStartTime(Long sessionId, LocalDateTime currentTime); + + public void updateAll(List sessions); } diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index 3d60b5e..847f77c 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -11,6 +11,7 @@ import com.waruru.areyouhere.session.domain.repository.SessionRepository; import com.waruru.areyouhere.session.exception.CurrentSessionNotFoundException; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; +import com.waruru.areyouhere.session.service.dto.UpdateSession; import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; @@ -62,6 +63,7 @@ public void deactivate(Long sessionId){ sessionRepository.save(session); } + @Override public void setStartTime(Long sessionId, LocalDateTime currentTime){ Session session = sessionRepository.findById(sessionId) .orElseThrow(SessionIdNotFoundException::new); @@ -69,5 +71,12 @@ public void setStartTime(Long sessionId, LocalDateTime currentTime){ sessionRepository.save(session); } + @Override + public void updateAll(List sessions){ + sessions.forEach(session -> { + sessionRepository.setSessionNameById(session.getName(), session.getId()); + }); + } + } diff --git a/src/main/java/com/waruru/areyouhere/session/service/dto/UpdateSession.java b/src/main/java/com/waruru/areyouhere/session/service/dto/UpdateSession.java new file mode 100644 index 0000000..ce5a53e --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/session/service/dto/UpdateSession.java @@ -0,0 +1,9 @@ +package com.waruru.areyouhere.session.service.dto; + +import lombok.Getter; + +@Getter +public class UpdateSession { + private Long id; + private String name; +} From c0e2cd1efbd9c37a7196256d842e61e434545a00 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Fri, 5 Apr 2024 17:32:38 +0900 Subject: [PATCH 04/19] =?UTF-8?q?Feat/Session=20=EA=B0=81=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=95=AD=EB=AA=A9=20id=20=EB=B0=98=ED=99=98=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attendance/service/AttendanceService.java | 1 - .../service/AttendanceServiceImpl.java | 21 ------------ .../domain/repository/AttendeeRepository.java | 6 ++-- .../dto/AttendeeAttendDetailInfo.java | 2 ++ .../repository/dto/SessionAttendeeInfo.java | 3 ++ .../service/dto/AttendeeDetailDto.java | 3 +- .../service/dto/SessionAttendees.java | 5 +-- .../query/AttendeeQueryServiceImpl.java | 33 +++++++------------ 8 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java index 9037f46..17d07a1 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java @@ -5,7 +5,6 @@ import java.util.List; public interface AttendanceService { - public AttendanceCount getAttendanceCount(long sessionId); public void setAbsentAfterDeactivation(long courseId, long sessionId); public void setAttend(Long sessionId, String attendanceName, Long attendeeId); diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java index 69c36b3..91de159 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java @@ -28,27 +28,6 @@ public class AttendanceServiceImpl implements AttendanceService { private final AttendeeRepository attendeeRepository; private final SessionRepository sessionRepository; - @Override - @Transactional(readOnly = true) - public AttendanceCount getAttendanceCount(long sessionId) { - List attendancesBySessionId = attendanceRepository.findAttendancesBySession_Id(sessionId); - - if (attendancesBySessionId.isEmpty()) { - return new AttendanceCount(0, 0); - } - int attendanceCount = 0; - int absenceCount = 0; - - for (Attendance attendance : attendancesBySessionId) { - if (attendance.isAttended()) { - attendanceCount++; - } else { - absenceCount++; - } - } - return new AttendanceCount(attendanceCount, absenceCount); - } - @Override public void setAbsentAfterDeactivation(long courseId, long sessionId) { diff --git a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java index 75144a7..d4ca50c 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java +++ b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java @@ -15,14 +15,14 @@ public interface AttendeeRepository extends JpaRepository { @Query(value = "SELECT * FROM attendee WHERE attendee.course_id = :courseId And attendee.id NOT IN (SELECT att.attendee_id FROM attendance as att WHERE att.session_id = :sessionId)", nativeQuery = true) public List findAbsenteeBySessionIdWhenNoRegister(@Param("courseId") Long courseId, @Param("sessionId") Long sessionId); - @Query(value = "SELECT atda.id as AttendanceId, atdee.name as AttendeeName, atdee.note as AttendeeNote, atda.is_attended as AttendanceStatus, atda.created_at as AttendanceTime \n" + @Query(value = "SELECT atda.id as AttendanceId, atdee.id as AttendeeId, atdee.name as AttendeeName, atdee.note as AttendeeNote, atda.is_attended as AttendanceStatus, atda.created_at as AttendanceTime \n" + "FROM attendee as atdee \n" + "INNER JOIN attendance as atda ON atdee.id = atda.attendee_id \n" + "WHERE atda.session_id = :sessionId", nativeQuery = true) public List findSessionAttendees(@Param("sessionId") Long sessionId); - @Query(value = "SELECT atda.id as AttendanceId, atdee.name as AttendeeName, atdee.note as AttendeeNote, atda.is_attended as AttendanceStatus, atda.created_at as AttendanceTime \n" + @Query(value = "SELECT atda.id as AttendanceId, atdee.id as AttendeeId, atdee.name as AttendeeName, atdee.note as AttendeeNote, atda.is_attended as AttendanceStatus, atda.created_at as AttendanceTime \n" + "FROM attendee as atdee \n" + "INNER JOIN attendance as atda ON atdee.id = atda.attendee_id \n" + "WHERE atda.session_id = :sessionId \n" @@ -49,7 +49,7 @@ public interface AttendeeRepository extends JpaRepository { + "GROUP BY a.course_id", nativeQuery = true) public List countAttendeesEachCourseByManagerId(@Param("managerId") Long managerId); - @Query(value = "SELECT atda.id as AttendanceId, sess.name as SessionName, atda.is_attended as AttendanceStatus, atda.created_at as AttendanceTime\n" + @Query(value = "SELECT atda.id as AttendanceId, sess.id as SessionId, sess.name as SessionName, atda.is_attended as AttendanceStatus, atda.created_at as AttendanceTime\n" + "from attendance atda\n" + "INNER JOIN session as sess ON atda.session_id = sess.id\n" + "where atda.attendee_id = :attendeeId\n" diff --git a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/AttendeeAttendDetailInfo.java b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/AttendeeAttendDetailInfo.java index 84f45c4..98bb647 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/AttendeeAttendDetailInfo.java +++ b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/AttendeeAttendDetailInfo.java @@ -5,6 +5,8 @@ public interface AttendeeAttendDetailInfo { public Long getAttendanceId(); + public Long getSessionId(); + public String getSessionName(); public Boolean getAttendanceStatus(); diff --git a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/SessionAttendeeInfo.java b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/SessionAttendeeInfo.java index b862a4a..835d932 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/SessionAttendeeInfo.java +++ b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/dto/SessionAttendeeInfo.java @@ -5,6 +5,9 @@ public interface SessionAttendeeInfo { public Long getAttendanceId(); + + public Long getAttendeeId(); + public String getAttendeeName(); public String getAttendeeNote(); diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/dto/AttendeeDetailDto.java b/src/main/java/com/waruru/areyouhere/attendee/service/dto/AttendeeDetailDto.java index 0596fa2..86396ab 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/dto/AttendeeDetailDto.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/dto/AttendeeDetailDto.java @@ -30,6 +30,7 @@ public AttendeeDetailDto(Attendee attendee, int attendance, int absence, List new AttendeeAttendeeDetail( attendeeAttendDetailInfo.getAttendanceId(), + attendeeAttendDetailInfo.getSessionId(), attendeeAttendDetailInfo.getSessionName(), attendeeAttendDetailInfo.getAttendanceStatus(), attendeeAttendDetailInfo.getAttendanceTime().toString() @@ -38,6 +39,6 @@ public AttendeeDetailDto(Attendee attendee, int attendance, int absence, List new IllegalArgumentException("참여자가 존재하지 않습니다.")); + .orElseThrow(IllegalArgumentException::new); - List attendanceInfoByAttendeeId = attendeeRepository.findAttendanceInfoByAttendeeId( - attendeeId); + List attendanceInfoByAttendeeId = attendeeRepository.findAttendanceInfoByAttendeeId(attendeeId); - int attendance = 0; - int absence = 0; + long attendance = attendanceInfoByAttendeeId.stream() + .filter(AttendeeAttendDetailInfo::getAttendanceStatus) + .count(); - for(AttendeeAttendDetailInfo attendDetailInfo : attendanceInfoByAttendeeId){ - if(attendDetailInfo.getAttendanceStatus()){ - attendance++; - }else{ - absence++; - } - } + long absence = attendanceInfoByAttendeeId.size() - attendance; return AttendeeDetailDto.builder() .attendee(attendee) - .attendance(attendance) - .absence(absence) + .attendance((int) attendance) + .absence((int) absence) .attendanceInfo(attendanceInfoByAttendeeId) .build(); } @@ -59,13 +53,8 @@ public DuplicateAttendees getDuplicatesAll(Long courseId, List newAttend DuplicateAttendees duplicateAttendees = new DuplicateAttendees(new LinkedList<>()); newAttendees.stream() - .filter(newAttendee -> { - if(!uniqueAttendees.add(newAttendee)){ - duplicated.add(newAttendee); - return true; - } - return false; - }) + .filter(newAttendee -> !uniqueAttendees.add(newAttendee)) + .peek(duplicated::add) .forEach(newAttendee -> duplicateAttendees.addDuplicateAttendee(null, newAttendee, null)); @@ -98,6 +87,7 @@ public List getSessionAttendeesIfExistsOrEmpty(Long sessionId) return sessionAttendees.stream().map(sessionAttendee -> SessionAttendees.builder() .attendanceId(sessionAttendee.getAttendanceId()) + .attendeeId(sessionAttendee.getAttendeeId()) .name(sessionAttendee.getAttendeeName()) .note(sessionAttendee.getAttendeeNote()) .attendanceStatus(sessionAttendee.getAttendanceStatus()) @@ -114,6 +104,7 @@ public List getSessionAbsenteesIfExistsOrEmpty(Long sessionId) return sessionAttendees.stream().map(sessionAttendee -> SessionAttendees.builder() .attendanceId(sessionAttendee.getAttendanceId()) + .attendeeId(sessionAttendee.getAttendeeId()) .name(sessionAttendee.getAttendeeName()) .note(sessionAttendee.getAttendeeNote()) .attendanceStatus(sessionAttendee.getAttendanceStatus()) From 6d45a6821eae75b942d7d9617ed8b8a3db430a9d Mon Sep 17 00:00:00 2001 From: SHEOM Date: Fri, 5 Apr 2024 21:52:03 +0900 Subject: [PATCH 05/19] =?UTF-8?q?Feat/OSIV:=20Open=20Session=20In=20View?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20=EB=81=84=EA=B8=B0.=20(#44)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yaml | 1 + src/main/resources/application-local.yaml | 1 + src/main/resources/application-release.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index ffe5625..dbf782b 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -14,6 +14,7 @@ spring: hibernate: format_sql: true database: mysql + open-in-view: false data: redis: host: ${REDIS_DATASOURCE_HOST} diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index e7afbf3..082cdc2 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -18,6 +18,7 @@ spring: properties: hibernate: format_sql: true + open-in-view: false data: redis: host: localhost diff --git a/src/main/resources/application-release.yaml b/src/main/resources/application-release.yaml index 83da293..88705df 100644 --- a/src/main/resources/application-release.yaml +++ b/src/main/resources/application-release.yaml @@ -14,6 +14,7 @@ spring: hibernate: format_sql: true database: mysql + open-in-view: false data: redis: host: ${REDIS_DATASOURCE_HOST} From ab764fb43ac3f75304beae966ede45ab103ae29a Mon Sep 17 00:00:00 2001 From: SHEOM Date: Mon, 8 Apr 2024 18:29:14 +0900 Subject: [PATCH 06/19] =?UTF-8?q?Feat/attendance=20=EC=B6=9C=EC=84=9D=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=EA=B3=BC=20=EC=B6=9C=EC=84=9D=20=EC=82=BD?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=EC=A0=90=20=EB=B6=84=EB=A6=AC=20(#45)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advice/AttendanceExceptionAdvice.java | 8 +- .../controller/AttendanceController.java | 93 ++++++------- .../controller/AuthCodeController.java | 12 +- .../CurrentAttendanceCountResponseDto.java | 2 +- .../service/AttendanceRDBService.java | 14 ++ .../service/AttendanceRDBServiceImpl.java | 105 +++++++++++++++ .../service/AttendanceRedisService.java | 21 ++- .../service/AttendanceRedisServiceImpl.java | 59 +++++--- .../attendance/service/AttendanceService.java | 14 +- .../service/AttendanceServiceImpl.java | 127 +++++++----------- ...nt.java => CurrentSessionAttendCount.java} | 7 +- .../controller/AttendeeController.java | 22 +-- .../attendee/service/AttendeeServiceImpl.java | 107 ++++++++------- .../service/query/AttendeeQueryService.java | 1 - .../course/controller/CourseController.java | 8 +- .../course/service/CourseService.java | 6 +- .../course/service/CourseServiceImpl.java | 13 +- .../repository/AuthCodeRedisRepository.java | 5 - .../session/service/SessionService.java | 1 + .../session/service/SessionServiceImpl.java | 51 +++---- .../command/SessionCommandService.java | 3 + .../command/SessionCommandServiceImpl.java | 17 ++- .../service/query/SessionQueryService.java | 5 + .../query/SessionQueryServiceImpl.java | 29 ++-- 24 files changed, 432 insertions(+), 298 deletions(-) create mode 100644 src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBService.java create mode 100644 src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBServiceImpl.java rename src/main/java/com/waruru/areyouhere/attendance/service/dto/{AttendanceCount.java => CurrentSessionAttendCount.java} (57%) diff --git a/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java index e33ec3c..9e96db2 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java @@ -19,7 +19,7 @@ public class AttendanceExceptionAdvice { @ExceptionHandler(SessionIdNotFoundException.class) - public ResponseEntity sessionIdNotFoundHandler(){ + public ResponseEntity sessionIdNotFoundHandler() { return RESPONSE_NOT_FOUND; } @@ -29,17 +29,17 @@ public ResponseEntity studentNameNotFoundHandler() { } @ExceptionHandler(AuthCodeNotFoundException.class) - public ResponseEntity authCodeNotFoundHandler(){ + public ResponseEntity authCodeNotFoundHandler() { return RESPONSE_NOT_FOUND; } @ExceptionHandler(AlreadyAttendException.class) - public ResponseEntity alreadyAttendHandler(){ + public ResponseEntity alreadyAttendHandler() { return RESPONSE_BAD_REQUEST; } @ExceptionHandler(DuplicateAuthCodeAttendException.class) - public ResponseEntity duplicateAuthCodeAttendHandler(){ + public ResponseEntity duplicateAuthCodeAttendHandler() { return RESPONSE_FORBIDDEN; } } diff --git a/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java b/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java index 272a96e..e281c4d 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java +++ b/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java @@ -7,15 +7,11 @@ import com.waruru.areyouhere.attendance.dto.request.UpdateAttendanceRequestDto; import com.waruru.areyouhere.attendance.exception.DuplicateAuthCodeAttendException; import com.waruru.areyouhere.attendance.service.AttendanceService; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendCount; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; -import com.waruru.areyouhere.attendee.service.AttendeeService; -import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; import com.waruru.areyouhere.common.annotation.LoginRequired; -import com.waruru.areyouhere.attendance.service.AttendanceRedisService; -import com.waruru.areyouhere.session.service.dto.AuthCodeInfo; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; -import java.time.LocalDateTime; import java.util.Arrays; import java.util.Base64; import java.util.List; @@ -40,111 +36,100 @@ @RequestMapping(AttendanceController.ATTENDANCE_API_URL) public class AttendanceController { public static final String ATTENDANCE_API_URL = "/api/attendance"; + @Value("${cookie.encode}") + private String COOKIE_ENCODE; - private final AttendanceRedisService attendanceRedisService; private final AttendanceService attendanceService; - private final AttendeeService attendeeService; - @Value("${cookie.encode}") - private String COOKIE_ENCODE; - //FIXME: 중복 인원인 경우 코드 중복이 생겨도 API 분리가 나아 보인다. 한 API에서 너무 많은 일을 하는 중이다. - // FIXME: 사실상 다른 형태의 response를 억지로 하나의 controller에서 반환한다고 봐도 무방하다. -> 프론트와 합의 후 변경. + //FIXME: 1. 중복 인원인 경우 코드 중복이 생겨도 API 분리가 나아 보인다. 한 API에서 너무 많은 일을 하는 중이다. + // FIXME: 2. 사실상 다른 형태의 response를 억지로 하나의 controller에서 반환한다고 봐도 무방하다. -> 프론트와 합의 후 변경. @PostMapping - public ResponseEntity attend(HttpServletRequest request, @RequestBody AttendRequestDto attendRequestDto){ + public ResponseEntity attend(HttpServletRequest request, + @RequestBody AttendRequestDto attendRequestDto) { String attendeeName = attendRequestDto.getAttendeeName(); String authCode = attendRequestDto.getAuthCode(); Long attendeeId = attendRequestDto.getAttendeeId(); - LocalDateTime attendanceTime = LocalDateTime.now(); - - - List nameSakeAttendees = attendanceRedisService.getNameSakeInfos(authCode, attendeeName); - // 동명이인 응답 - if(attendeeId == null && nameSakeAttendees.size() > 1){ - return ResponseEntity.status(HttpStatus.MULTIPLE_CHOICES).body( - AttendResponseDto.builder() - .attendeeNotes(nameSakeAttendees) - .build() - ); - } - - AuthCodeInfo authCodeInfo = attendanceRedisService.isAttendPossible(authCode, attendeeName, attendeeId); checkAuthCodeCookie(request.getCookies(), authCode); - attendanceService.setAttend(authCodeInfo.getSessionId(), attendeeName, attendeeId); - - + AttendResponseDto attendResponseDto = attendanceService.attend(attendeeName, authCode, attendeeId); HttpCookie authCodeCookie = getAuthCodeCookie(authCode); + // FIXME: 3. 그러다보니 도메인 영역의 코드를 이해해야 생기는 이런 나쁜 코드가 생긴다. + return attendResponseDto.getAttendanceName() == null ? + ResponseEntity.status(HttpStatus.MULTIPLE_CHOICES) + .body(attendResponseDto) + : ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, authCodeCookie.toString()) + .body(attendResponseDto); - return ResponseEntity.ok() - .header(HttpHeaders.SET_COOKIE, authCodeCookie.toString()) - .body( - AttendResponseDto.builder() - .attendanceName(attendeeName) - .courseName(authCodeInfo.getCourseName()) - .sessionName(authCodeInfo.getSessionName()) - .attendanceTime(attendanceTime).build() - ); } @LoginRequired @PutMapping - ResponseEntity update(@RequestBody UpdateAttendanceRequestDto updateAttendanceRequestDto){ + ResponseEntity update(@RequestBody UpdateAttendanceRequestDto updateAttendanceRequestDto) { Long sessionId = updateAttendanceRequestDto.getSessionId(); List updateAttendance = updateAttendanceRequestDto.getUpdateAttendances(); - attendanceService.setAttendanceStatuses(sessionId, updateAttendance); + attendanceService.updateAllStatuses(sessionId, updateAttendance); return ResponseEntity.ok().build(); } + //FIXME: 프론트와 합의하여 Redis data는 AuthCode로 일관되게 받아올 수 있도록 하는 것이 좋을 것 같다. @LoginRequired @GetMapping - ResponseEntity getCurrentAttendancesCount(@RequestParam("courseId") Long courseId, @RequestParam("sessionId") Long sessionId){ - int currentAttendance = attendanceService.currentAttendance(sessionId); - int total = attendeeService.getAllByCourseId(courseId); - return ResponseEntity.ok(new CurrentAttendanceCountResponseDto(currentAttendance, total)); + ResponseEntity getCurrentAttendancesCount( + @RequestParam("courseId") Long courseId, @RequestParam("sessionId") Long sessionId) { + CurrentSessionAttendCount currentSessionAttendCount = attendanceService.getCurrentSessionAttendCount(sessionId); + return ResponseEntity.ok().body( + new CurrentAttendanceCountResponseDto( + currentSessionAttendCount.getTotal(), + currentSessionAttendCount.getAttendanceCount() + ) + ); } @LoginRequired @GetMapping("/detail") - ResponseEntity getCurrentSessionAttendeeAttendance(@RequestParam("authCode") String authCode){ - return ResponseEntity.ok(attendanceRedisService.getCurrentSessionAttendanceInfo(authCode)); + ResponseEntity getCurrentSessionAttendeeAttendance( + @RequestParam("authCode") String authCode) { + return ResponseEntity.ok(attendanceService.getCurrentSessionAttendeesAndAbsentees(authCode)); } - private String encodeCookieValue(String string){ + private String encodeCookieValue(String string) { return Base64.getEncoder().encodeToString((string).getBytes()); } - private String encodeCookieKey(String string){ + private String encodeCookieKey(String string) { StringBuilder stringBuilder = new StringBuilder(); - for(char c : string.toCharArray()){ + for (char c : string.toCharArray()) { stringBuilder.append((c ^ COOKIE_ENCODE.charAt(0))); } return stringBuilder.toString(); } - private HttpCookie getAuthCodeCookie(String authCode){ + private HttpCookie getAuthCodeCookie(String authCode) { return ResponseCookie.from(encodeCookieKey(authCode), encodeCookieValue(authCode)) .maxAge(60 * 30) .httpOnly(true) .build(); } - private void checkAuthCodeCookie(Cookie[] cookies, String authCode){ - if(cookies == null) + private void checkAuthCodeCookie(Cookie[] cookies, String authCode) { + if (cookies == null) { return; + } Optional authCookie = Arrays.stream(cookies) .filter(cookie -> cookie.getName().equals(encodeCookieKey(authCode))) .findFirst(); authCookie.ifPresent(cookie -> { - if(new String(Base64.getDecoder().decode(cookie.getValue())).equals(authCode)) + if (new String(Base64.getDecoder().decode(cookie.getValue())).equals(authCode)) { throw new DuplicateAuthCodeAttendException(); + } }); } - } diff --git a/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java b/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java index 91eb9af..35128e0 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java +++ b/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java @@ -1,14 +1,13 @@ package com.waruru.areyouhere.attendance.controller; -import com.waruru.areyouhere.attendance.service.AttendanceService; +import com.waruru.areyouhere.attendance.service.AttendanceRDBService; import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.course.service.CourseService; import com.waruru.areyouhere.session.domain.entity.Session; import com.waruru.areyouhere.attendance.dto.request.AuthCodeDeactivationRequestDto; import com.waruru.areyouhere.attendance.dto.request.AuthCodeRequestDto; import com.waruru.areyouhere.attendance.service.AttendanceRedisService; -import com.waruru.areyouhere.session.service.SessionService; import com.waruru.areyouhere.session.service.command.SessionCommandService; import com.waruru.areyouhere.session.service.query.SessionQueryService; import java.time.LocalDateTime; @@ -28,14 +27,14 @@ public class AuthCodeController { public static final String AUTH_CODE_API_URL = "/api/auth-code"; private final AttendanceRedisService attendanceRedisService; - private final AttendanceService attendanceService; + private final AttendanceRDBService attendanceRDBService; private final SessionCommandService sessionCommandService; private final SessionQueryService sessionQueryService; private final CourseService courseService; @PostMapping - public ResponseEntity create(@RequestBody AuthCodeRequestDto authCodeRequestDto){ + public ResponseEntity create(@RequestBody AuthCodeRequestDto authCodeRequestDto) { LocalDateTime currentTime = LocalDateTime.now(); Long sessionId = authCodeRequestDto.getSessionId(); Long courseId = authCodeRequestDto.getCourseId(); @@ -46,7 +45,8 @@ public ResponseEntity create(@RequestBody AuthCodeRequestDto authCodeReq } @PostMapping("/deactivate") - public ResponseEntity deactivate(@RequestBody AuthCodeDeactivationRequestDto authCodeDeactivationRequestDto){ + public ResponseEntity deactivate( + @RequestBody AuthCodeDeactivationRequestDto authCodeDeactivationRequestDto) { Long sessionId = authCodeDeactivationRequestDto.getSessionId(); Long courseId = authCodeDeactivationRequestDto.getCourseId(); @@ -55,7 +55,7 @@ public ResponseEntity deactivate(@RequestBody AuthCodeDeactivationRe sessionQueryService.checkNotDeactivated(sessionId); sessionCommandService.deactivate(sessionId); attendanceRedisService.deactivate(authCode); - attendanceService.setAbsentAfterDeactivation(courseId, sessionId); + attendanceRDBService.setAbsentAfterDeactivation(courseId, sessionId); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/waruru/areyouhere/attendance/dto/response/CurrentAttendanceCountResponseDto.java b/src/main/java/com/waruru/areyouhere/attendance/dto/response/CurrentAttendanceCountResponseDto.java index 78dea3d..1f7e002 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/dto/response/CurrentAttendanceCountResponseDto.java +++ b/src/main/java/com/waruru/areyouhere/attendance/dto/response/CurrentAttendanceCountResponseDto.java @@ -6,6 +6,6 @@ @Data @AllArgsConstructor public class CurrentAttendanceCountResponseDto { - private int attendances; private int total; + private int attendances; } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBService.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBService.java new file mode 100644 index 0000000..cbbc93f --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBService.java @@ -0,0 +1,14 @@ +package com.waruru.areyouhere.attendance.service; + +import com.waruru.areyouhere.attendance.dto.UpdateAttendance; +import java.util.List; + +public interface AttendanceRDBService { + public void setAbsentAfterDeactivation(long courseId, long sessionId); + + public void setAttend(Long sessionId, String attendanceName, Long attendeeId); + + public void setAttendanceStatuses(Long sessionId, List updateAttendances); + + public int currentAttendance(Long sessionId); +} diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBServiceImpl.java new file mode 100644 index 0000000..403b81f --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBServiceImpl.java @@ -0,0 +1,105 @@ +package com.waruru.areyouhere.attendance.service; + + +import com.waruru.areyouhere.attendance.domain.entity.Attendance; +import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; +import com.waruru.areyouhere.attendance.dto.UpdateAttendance; +import com.waruru.areyouhere.attendee.domain.entity.Attendee; +import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; +import com.waruru.areyouhere.session.domain.entity.Session; +import com.waruru.areyouhere.session.domain.repository.SessionRepository; +import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Slf4j +@Transactional +public class AttendanceRDBServiceImpl implements AttendanceRDBService { + + private final AttendanceRepository attendanceRepository; + private final AttendeeRepository attendeeRepository; + private final SessionRepository sessionRepository; + + @Override + public void setAbsentAfterDeactivation(long courseId, long sessionId) { + + List absenteeBySessionId = attendeeRepository.findAbsenteeBySessionIdWhenNoRegister(courseId, + sessionId); + Session session = sessionRepository.findById(sessionId).orElseThrow(SessionIdNotFoundException::new); + List attendances = absenteeBySessionId.stream().map(attendee -> Attendance.builder() + .attendee((attendee)) + .session(session) + .isAttended(false) + .build()).toList(); + attendanceRepository.saveAll(attendances); + } + + @Async + public void setAttend(Long sessionId, String attendanceName, Long attendeeId) { + Session session = sessionRepository.findById(sessionId) + .orElseThrow(SessionIdNotFoundException::new); + Long courseId = session.getCourse().getId(); // lazy loading? + List attendeesByCourseId = attendeeRepository.findAttendeesByCourse_Id(courseId); + + Attendee attendee = getAttendee(attendanceName, attendeeId, + attendeesByCourseId); + + // TODO : attendeesByCourseId null 및 empty 체크 + + Attendance attendance = Attendance.builder() + .session(session) + .isAttended(true) + .attendee(attendee) + .build(); + attendanceRepository.save(attendance); + + } + + + public void setAttendanceStatuses(Long sessionId, List updateAttendances) { + List attendancesToUpdate = updateAttendances.stream() + .map(updateAttendance -> { + Attendance attendance = attendanceRepository.findById(updateAttendance.getAttendanceId()) + .orElseThrow(SessionIdNotFoundException::new); + attendance.setAttended(updateAttendance.isAttendanceStatus()); + + return attendance; + }) + .collect(Collectors.toList()); + + attendanceRepository.saveAll(attendancesToUpdate); + } + + @Transactional(readOnly = true) + public int currentAttendance(Long sessionId) { + List attendancesBySessionId = attendanceRepository.findAttendancesBySession_Id(sessionId); + if (attendancesBySessionId == null || attendancesBySessionId.isEmpty()) { + return 0; + } else { + return attendancesBySessionId.size(); + } + } + + + // AttendeeId가 null이 아니라는 것은 duplicatedAttendee가 발생하여 Id 기준으로 찾아야 한다는 것. + private Attendee getAttendee(String attendanceName, Long attendeeId, List attendeesByCourseId) { + return attendeeId == null ? + attendeesByCourseId.stream() + .filter(s -> s.getName().equals(attendanceName)) + .findFirst() + .orElse(null) : + attendeesByCourseId.stream() + .filter(s -> s.getId().equals(attendeeId)) + .findFirst() + .orElse(null); + } + + +} diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisService.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisService.java index b512bc3..5f43f1f 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisService.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisService.java @@ -1,5 +1,7 @@ package com.waruru.areyouhere.attendance.service; +import com.waruru.areyouhere.attendance.domain.entity.AttendeeRedisData; +import com.waruru.areyouhere.attendance.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; import com.waruru.areyouhere.course.domain.entity.Course; @@ -11,12 +13,27 @@ public interface AttendanceRedisService { public List getNameSakeInfos(String authCode, String attendeeName); - public AuthCodeInfo isAttendPossible(String authCode, String attendanceName, Long attendeeId); + public AuthCodeInfo isAttendPossible(String authCode, String attendanceName, Long attendeeId); public String createAuthCode(Course course, Session sessionId, LocalDateTime currentTime); public void deactivate(String authCode); - public CurrentSessionAttendeeAttendance getCurrentSessionAttendanceInfo(String authCode); + public CurrentSessionAttendeeAttendance getCurrentSessionAttendees(String authCode); + + public void setAttendInRedis(String authCode, AttendeeRedisData attendeeInfo); + + public AttendeeRedisData findByNameIfNotDuplicatedOrId(String attendeeName, Long attendeeId, + CurrentSessionAttendanceInfo currentSessionAttendanceInfoData); + + public CurrentSessionAttendanceInfo getSessionAttendanceInfoOrThrow(String authCode); + + public String findAuthCodeBySessionId(Long sessionId); + + public int getTotalAttendees(String authCode); + + public int getAttendCount(String authCode); + + } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisServiceImpl.java index f24b48f..882876c 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisServiceImpl.java @@ -30,20 +30,19 @@ @Service @RequiredArgsConstructor -@Transactional public class AttendanceRedisServiceImpl implements AttendanceRedisService { private final AuthCodeRedisRepository authCodeRedisRepository; private final SessionIdRedisRepository sessionIdRedisRepository; + private final AttendanceRedisRepository attendanceRedisRepository; private final AttendeeRepository attendeeRepository; private final RandomIdentifierGenerator randomIdentifierGenerator; - private final AttendanceRedisRepository attendanceRedisRepository; + @Override public List getNameSakeInfos(String authCode, String attendeeName) { - CurrentSessionAttendanceInfo currentSessionAttendanceInfoData = authCodeRedisRepository - .findById(authCode) - .orElseThrow(AuthCodeNotFoundException::new); + CurrentSessionAttendanceInfo currentSessionAttendanceInfoData = getSessionAttendanceInfoOrThrow( + authCode); List attendees = currentSessionAttendanceInfoData.getAttendees(); return attendees.stream() @@ -59,19 +58,16 @@ public List getNameSakeInfos(String authCode, String attendeeName) @Override public AuthCodeInfo isAttendPossible(String authCode, String attendeeName, Long attendeeId) { - CurrentSessionAttendanceInfo currentSessionAttendanceInfoData = authCodeRedisRepository - .findById(authCode) - .orElseThrow(AuthCodeNotFoundException::new); + CurrentSessionAttendanceInfo currentSessionAttendanceInfoData = getSessionAttendanceInfoOrThrow( + authCode); - AttendeeRedisData attendeeInfo = getAttendeeInSession(attendeeName, attendeeId, + AttendeeRedisData attendeeInfo = findByNameIfNotDuplicatedOrId(attendeeName, attendeeId, currentSessionAttendanceInfoData); if (attendanceRedisRepository.isAlreadyAttended(authCode, attendeeInfo)) { throw new AlreadyAttendException(); } - attendanceRedisRepository.setAttend(authCode, attendeeInfo); - return AuthCodeInfo.builder() .courseName(currentSessionAttendanceInfoData.getCourseName()) .sessionName(currentSessionAttendanceInfoData.getSessionName()) @@ -79,6 +75,17 @@ public AuthCodeInfo isAttendPossible(String authCode, String attendeeName, Long .build(); } + public CurrentSessionAttendanceInfo getSessionAttendanceInfoOrThrow(String authCode) { + return authCodeRedisRepository + .findById(authCode) + .orElseThrow(AuthCodeNotFoundException::new); + } + + @Override + public void setAttendInRedis(String authCode, AttendeeRedisData attendeeInfo) { + attendanceRedisRepository.setAttend(authCode, attendeeInfo); + } + @Override public String createAuthCode(Course course, Session session, LocalDateTime currentTime) { @@ -110,8 +117,8 @@ public String createAuthCode(Course course, Session session, LocalDateTime curre // TODO : sessionId 검증, 해당 sessionId가 user 소유인지 검증. @Override public void deactivate(String authCode) { - CurrentSessionAttendanceInfo authCodeByCurrentSessionAttendanceInfo = authCodeRedisRepository.findById(authCode) - .orElseThrow(AuthCodeNotFoundException::new); + CurrentSessionAttendanceInfo authCodeByCurrentSessionAttendanceInfo = getSessionAttendanceInfoOrThrow( + authCode); authCodeRedisRepository.delete(authCodeByCurrentSessionAttendanceInfo); sessionIdRedisRepository.deleteById(authCodeByCurrentSessionAttendanceInfo.getSessionId()); @@ -119,9 +126,9 @@ public void deactivate(String authCode) { } - public CurrentSessionAttendeeAttendance getCurrentSessionAttendanceInfo(String authCode) { - CurrentSessionAttendanceInfo currentSessionAttendanceInfoData = authCodeRedisRepository.findById(authCode) - .orElseThrow(AuthCodeNotFoundException::new); + public CurrentSessionAttendeeAttendance getCurrentSessionAttendees(String authCode) { + CurrentSessionAttendanceInfo currentSessionAttendanceInfoData = getSessionAttendanceInfoOrThrow( + authCode); List attendees = new LinkedList<>(); List absentees = new LinkedList<>(); Set attendeesChecker = attendanceRedisRepository.getAttendees(authCode); @@ -140,8 +147,9 @@ public CurrentSessionAttendeeAttendance getCurrentSessionAttendanceInfo(String a .build(); } - private AttendeeRedisData getAttendeeInSession(String attendeeName, Long attendeeId, - CurrentSessionAttendanceInfo currentSessionAttendanceInfoData) { + @Override + public AttendeeRedisData findByNameIfNotDuplicatedOrId(String attendeeName, Long attendeeId, + CurrentSessionAttendanceInfo currentSessionAttendanceInfoData) { AttendeeRedisData attendeeInfo = currentSessionAttendanceInfoData.getAttendees().stream() .filter(att -> att.getName().equals(attendeeName)) .findAny() @@ -156,6 +164,21 @@ private AttendeeRedisData getAttendeeInSession(String attendeeName, Long attende return attendeeInfo; } + public String findAuthCodeBySessionId(Long sessionId) { + return sessionIdRedisRepository.findById(sessionId) + .orElseThrow(AuthCodeNotFoundException::new).getAuthCode(); + } + + + public int getTotalAttendees(String authCode) { + return authCodeRedisRepository.findById(authCode) + .orElseThrow(AuthCodeNotFoundException::new).getAttendees().size(); + } + + public int getAttendCount(String authCode) { + return attendanceRedisRepository.getAttendees(authCode).size(); + } + private String generateAuthCode() { String generatedAuthCode = ""; while (true) { diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java index 17d07a1..bf85290 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceService.java @@ -1,14 +1,18 @@ package com.waruru.areyouhere.attendance.service; import com.waruru.areyouhere.attendance.dto.UpdateAttendance; -import com.waruru.areyouhere.attendance.service.dto.AttendanceCount; +import com.waruru.areyouhere.attendance.dto.response.AttendResponseDto; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendCount; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import java.util.List; public interface AttendanceService { - public void setAbsentAfterDeactivation(long courseId, long sessionId); - public void setAttend(Long sessionId, String attendanceName, Long attendeeId); + public AttendResponseDto attend(String attendeeName, String authCode, Long attendeeId); - public void setAttendanceStatuses(Long sessionId , List updateAttendances); - public int currentAttendance(Long sessionId); + public void updateAllStatuses(Long sessionId, List updateAttendances); + + public CurrentSessionAttendCount getCurrentSessionAttendCount(Long sessionId); + + public CurrentSessionAttendeeAttendance getCurrentSessionAttendeesAndAbsentees(String authCode); } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java index 91de159..e0f18c5 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java @@ -1,105 +1,74 @@ package com.waruru.areyouhere.attendance.service; - -import com.waruru.areyouhere.attendance.domain.entity.Attendance; -import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; +import com.waruru.areyouhere.attendance.domain.entity.AttendeeRedisData; import com.waruru.areyouhere.attendance.dto.UpdateAttendance; -import com.waruru.areyouhere.attendance.service.dto.AttendanceCount; -import com.waruru.areyouhere.attendee.domain.entity.Attendee; -import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; -import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.session.domain.repository.SessionRepository; -import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; +import com.waruru.areyouhere.attendance.dto.response.AttendResponseDto; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendCount; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; +import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; +import com.waruru.areyouhere.session.service.dto.AuthCodeInfo; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.List; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +// TODO: 출석 로직이 너무 비대해서 facade 패턴으로 상위 레포지토리를 분리했는데 출석 외의 로직이 방대하지 않아서 +// TODO: 그 외엔 필요가 없어보인다.. @Service @RequiredArgsConstructor -@Slf4j -@Transactional public class AttendanceServiceImpl implements AttendanceService { - - private final AttendanceRepository attendanceRepository; - private final AttendeeRepository attendeeRepository; - private final SessionRepository sessionRepository; + private final AttendanceRDBService attendanceRDBService; + private final AttendanceRedisService attendanceRedisService; @Override - public void setAbsentAfterDeactivation(long courseId, long sessionId) { - - List absenteeBySessionId = attendeeRepository.findAbsenteeBySessionIdWhenNoRegister(courseId, - sessionId); - Session session = sessionRepository.findById(sessionId).orElseThrow(SessionIdNotFoundException::new); - List attendances = absenteeBySessionId.stream().map(attendee -> Attendance.builder() - .attendee((attendee)) - .session(session) - .isAttended(false) - .build()).toList(); - attendanceRepository.saveAll(attendances); - } - - @Async - public void setAttend(Long sessionId, String attendanceName, Long attendeeId) { - Session session = sessionRepository.findById(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - Long courseId = session.getCourse().getId(); // lazy loading? - List attendeesByCourseId = attendeeRepository.findAttendeesByCourse_Id(courseId); - - Attendee attendee = getAttendee(attendanceName, attendeeId, - attendeesByCourseId); + @Transactional + public AttendResponseDto attend(String attendeeName, String authCode, Long attendeeId) { + LocalDateTime attendanceTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); + List nameSakeAttendees = attendanceRedisService.getNameSakeInfos(authCode, attendeeName); + + // 동명이인 응답 + if (attendeeId == null && nameSakeAttendees.size() > 1) { + return AttendResponseDto.builder() + .attendeeNotes(nameSakeAttendees) + .build(); + } - // TODO : attendeesByCourseId null 및 empty 체크 + AuthCodeInfo authCodeInfo = attendanceRedisService.isAttendPossible(authCode, attendeeName, attendeeId); + attendanceRDBService.setAttend(authCodeInfo.getSessionId(), attendeeName, attendeeId); + AttendeeRedisData attendeeInSession = attendanceRedisService.findByNameIfNotDuplicatedOrId(attendeeName, + attendeeId, + attendanceRedisService.getSessionAttendanceInfoOrThrow(authCode)); + attendanceRedisService.setAttendInRedis(authCode, attendeeInSession); - Attendance attendance = Attendance.builder() - .session(session) - .isAttended(true) - .attendee(attendee) - .build(); - attendanceRepository.save(attendance); + return AttendResponseDto.builder() + .attendanceName(attendeeName) + .courseName(authCodeInfo.getCourseName()) + .sessionName(authCodeInfo.getSessionName()) + .attendanceTime(attendanceTime).build(); } - - public void setAttendanceStatuses(Long sessionId, List updateAttendances) { - List attendancesToUpdate = updateAttendances.stream() - .map(updateAttendance -> { - Attendance attendance = attendanceRepository.findById(updateAttendance.getAttendanceId()) - .orElseThrow(SessionIdNotFoundException::new); - attendance.setAttended(updateAttendance.isAttendanceStatus()); - - return attendance; - }) - .collect(Collectors.toList()); - - attendanceRepository.saveAll(attendancesToUpdate); + @Override + @Transactional + public void updateAllStatuses(Long sessionId, List updateAttendances) { + attendanceRDBService.setAttendanceStatuses(sessionId, updateAttendances); } + @Override @Transactional(readOnly = true) - public int currentAttendance(Long sessionId) { - List attendancesBySessionId = attendanceRepository.findAttendancesBySession_Id(sessionId); - if (attendancesBySessionId == null || attendancesBySessionId.isEmpty()) { - return 0; - } else { - return attendancesBySessionId.size(); - } + public CurrentSessionAttendCount getCurrentSessionAttendCount(Long sessionId) { + String authCode = attendanceRedisService.findAuthCodeBySessionId(sessionId); + int total = attendanceRedisService.getTotalAttendees(authCode); + int attendeeCount = attendanceRedisService.getAttendCount(authCode); + return new CurrentSessionAttendCount(total, attendeeCount); } - - // AttendeeId가 null이 아니라는 것은 duplicatedAttendee가 발생하여 Id 기준으로 찾아야 한다는 것. - private Attendee getAttendee(String attendanceName, Long attendeeId, List attendeesByCourseId) { - return attendeeId == null ? - attendeesByCourseId.stream() - .filter(s -> s.getName().equals(attendanceName)) - .findFirst() - .orElse(null) : - attendeesByCourseId.stream() - .filter(s -> s.getId().equals(attendeeId)) - .findFirst() - .orElse(null); + @Override + @Transactional(readOnly = true) + public CurrentSessionAttendeeAttendance getCurrentSessionAttendeesAndAbsentees(String authCode) { + return attendanceRedisService.getCurrentSessionAttendees(authCode); } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/dto/AttendanceCount.java b/src/main/java/com/waruru/areyouhere/attendance/service/dto/CurrentSessionAttendCount.java similarity index 57% rename from src/main/java/com/waruru/areyouhere/attendance/service/dto/AttendanceCount.java rename to src/main/java/com/waruru/areyouhere/attendance/service/dto/CurrentSessionAttendCount.java index c51b456..2e25603 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/dto/AttendanceCount.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/dto/CurrentSessionAttendCount.java @@ -1,12 +1,11 @@ package com.waruru.areyouhere.attendance.service.dto; import lombok.AllArgsConstructor; -import lombok.Data; import lombok.Getter; @Getter @AllArgsConstructor -public class AttendanceCount { - private int attendees; - private int absentees; +public class CurrentSessionAttendCount { + private int total; + private int attendanceCount; } diff --git a/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java b/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java index 6c6b2ab..7d93b8b 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java +++ b/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java @@ -37,7 +37,7 @@ public class AttendeeController { @LoginRequired @GetMapping - public ResponseEntity getClassAttendees(@RequestParam("courseId") Long courseId){ + public ResponseEntity getClassAttendees(@RequestParam("courseId") Long courseId) { List classAttendees = attendeeQueryService.getClassAttendeesIfExistsOrEmpty(courseId); return ResponseEntity.ok(ClassAttendeesResponseDto.builder() @@ -47,34 +47,38 @@ public ResponseEntity getClassAttendees(@RequestParam @LoginRequired @PostMapping - public ResponseEntity create(@RequestBody NewAttendeesRequestDto newAttendeesRequestDto){ - attendeeCommandService.createAll(newAttendeesRequestDto.getCourseId(), newAttendeesRequestDto.getNewAttendees()); + public ResponseEntity create(@RequestBody NewAttendeesRequestDto newAttendeesRequestDto) { + attendeeCommandService.createAll(newAttendeesRequestDto.getCourseId(), + newAttendeesRequestDto.getNewAttendees()); return ResponseEntity.ok().build(); } @LoginRequired @PostMapping("/delete") - public ResponseEntity delete(@RequestBody DeleteAttendeesRequestDto deleteAttendeesRequestDto){ + public ResponseEntity delete(@RequestBody DeleteAttendeesRequestDto deleteAttendeesRequestDto) { attendeeCommandService.deleteAll(deleteAttendeesRequestDto.getAttendeeIds()); return ResponseEntity.ok().build(); } @LoginRequired @PostMapping("/duplicate") - public ResponseEntity checkDuplicate(@RequestBody DuplicateCheckAttendeesRequestDto duplicateCheckAttendeesRequestDto){ - return ResponseEntity.ok(attendeeQueryService.getDuplicatesAll(duplicateCheckAttendeesRequestDto.getCourseId(), duplicateCheckAttendeesRequestDto.getNewAttendees())); + public ResponseEntity checkDuplicate( + @RequestBody DuplicateCheckAttendeesRequestDto duplicateCheckAttendeesRequestDto) { + return ResponseEntity.ok(attendeeQueryService.getDuplicatesAll(duplicateCheckAttendeesRequestDto.getCourseId(), + duplicateCheckAttendeesRequestDto.getNewAttendees())); } @LoginRequired @GetMapping("/detail") - public ResponseEntity getAttendeeDetail(@RequestParam("attendeeId") Long attendeeId){ + public ResponseEntity getAttendeeDetail(@RequestParam("attendeeId") Long attendeeId) { return ResponseEntity.ok(attendeeQueryService.getAttendanceCount(attendeeId)); } @LoginRequired @PutMapping - public ResponseEntity update(@RequestBody UpdateAttendeesRequestDto UpdateAttendeesRequestDto){ - attendeeCommandService.updateAll(UpdateAttendeesRequestDto.getCourseId(), UpdateAttendeesRequestDto.getUpdatedAttendees()); + public ResponseEntity update(@RequestBody UpdateAttendeesRequestDto UpdateAttendeesRequestDto) { + attendeeCommandService.updateAll(UpdateAttendeesRequestDto.getCourseId(), + UpdateAttendeesRequestDto.getUpdatedAttendees()); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java index ec103cb..2f5dd73 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java @@ -31,21 +31,20 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - // TODO: AttendeeService가 너무 방대해지고 있다. 사실 기능 분리도 함수마다 안한 편인데도 이미 크다. // TODO: AttendeeService를 분리하고 두 layer를 두는 것이 좋을 것 같다. @Service @RequiredArgsConstructor @Transactional -public class AttendeeServiceImpl implements AttendeeService{ +public class AttendeeServiceImpl implements AttendeeService { private final AttendeeRepository attendeeRepository; private final AttendanceRepository attendanceRepository; private final AttendeeBatchRepository attendeeBatchRepository; private final CourseRepository courseRepository; - public void createAll(Long courseId, List newAttendees){ + public void createAll(Long courseId, List newAttendees) { Course course = courseRepository.findById(courseId) .orElseThrow(CourseNotFoundException::new); @@ -55,14 +54,14 @@ public void createAll(Long courseId, List newAttendees){ List attendeesToSave = new LinkedList<>(); newAttendees.forEach(attendeeInfo -> { - if(attendeeInfo.getId() != null){ + if (attendeeInfo.getId() != null) { attendeeToUpdate.add(Attendee.builder() .id(attendeeInfo.getId()) .course(course) .name(attendeeInfo.getName()) .note(attendeeInfo.getNote()) .build()); - }else{ + } else { attendeesToSave.add(Attendee.builder() .course(course) .name(attendeeInfo.getName()) @@ -76,7 +75,7 @@ public void createAll(Long courseId, List newAttendees){ } @Override - public DuplicateAttendees getDuplicatesAll(Long courseId, List newAttendees){ + public DuplicateAttendees getDuplicatesAll(Long courseId, List newAttendees) { Set uniqueAttendees = new HashSet<>(); Set duplicated = new HashSet<>(); @@ -84,7 +83,7 @@ public DuplicateAttendees getDuplicatesAll(Long courseId, List newAttend newAttendees.stream() .filter(newAttendee -> { - if(!uniqueAttendees.add(newAttendee)){ + if (!uniqueAttendees.add(newAttendee)) { duplicated.add(newAttendee); return true; } @@ -92,7 +91,6 @@ public DuplicateAttendees getDuplicatesAll(Long courseId, List newAttend }) .forEach(newAttendee -> duplicateAttendees.addDuplicateAttendee(null, newAttendee, null)); - duplicated.forEach(newAttendee -> duplicateAttendees.addDuplicateAttendee(null, newAttendee, null)); getAlreadyExists(courseId, newAttendees, duplicateAttendees); @@ -100,82 +98,87 @@ public DuplicateAttendees getDuplicatesAll(Long courseId, List newAttend } @Transactional(readOnly = true) - public DuplicateAttendees getAlreadyExists(Long courseId, List newAttendees, DuplicateAttendees duplicateAttendees){ + public DuplicateAttendees getAlreadyExists(Long courseId, List newAttendees, + DuplicateAttendees duplicateAttendees) { List attendeesByCourseId = attendeeRepository.findAttendeesByCourse_Id(courseId); Set attendeesAlreadyExists = Set.copyOf(newAttendees); attendeesByCourseId.stream() .filter(attendee -> attendeesAlreadyExists.contains(attendee.getName())) - .forEach(attendee -> duplicateAttendees.addDuplicateAttendee(attendee.getId(),attendee.getName(), attendee.getNote())); + .forEach(attendee -> duplicateAttendees.addDuplicateAttendee(attendee.getId(), attendee.getName(), + attendee.getNote())); return duplicateAttendees; } // TODO : courseId 검증 -> 해당 course의 attendee인지. - public void deleteAll(List deleteAttendees){ + public void deleteAll(List deleteAttendees) { attendanceRepository.deleteAllByAttendeeIds(deleteAttendees); attendeeRepository.deleteAllByIds(deleteAttendees); } @Transactional(readOnly = true) - public List getSessionAttendeesIfExistsOrEmpty(Long sessionId){ + public List getSessionAttendeesIfExistsOrEmpty(Long sessionId) { List sessionAttendees = attendeeRepository.findSessionAttendees(sessionId); - if(sessionAttendees == null || sessionAttendees.isEmpty()) + if (sessionAttendees == null || sessionAttendees.isEmpty()) { throw new SessionAttendeesEmptyException(); + } return sessionAttendees.stream().map(sessionAttendee -> SessionAttendees.builder() - .attendanceId(sessionAttendee.getAttendanceId()) - .name(sessionAttendee.getAttendeeName()) - .note(sessionAttendee.getAttendeeNote()) - .attendanceStatus(sessionAttendee.getAttendanceStatus()) - .attendanceTime(sessionAttendee.getAttendanceTime()) - .build()).toList(); + .attendanceId(sessionAttendee.getAttendanceId()) + .name(sessionAttendee.getAttendeeName()) + .note(sessionAttendee.getAttendeeNote()) + .attendanceStatus(sessionAttendee.getAttendanceStatus()) + .attendanceTime(sessionAttendee.getAttendanceTime()) + .build()).toList(); } @Transactional(readOnly = true) - public List getSessionAbsenteesIfExistsOrEmpty(Long sessionId){ + public List getSessionAbsenteesIfExistsOrEmpty(Long sessionId) { List sessionAttendees = attendeeRepository.findSessionOnlyAbsentee(sessionId); - if(sessionAttendees == null || sessionAttendees.isEmpty()) + if (sessionAttendees == null || sessionAttendees.isEmpty()) { throw new SessionAttendeesEmptyException(); + } return sessionAttendees.stream().map(sessionAttendee -> SessionAttendees.builder() - .attendanceId(sessionAttendee.getAttendanceId()) - .name(sessionAttendee.getAttendeeName()) - .note(sessionAttendee.getAttendeeNote()) - .attendanceStatus(sessionAttendee.getAttendanceStatus()) - .attendanceTime(sessionAttendee.getAttendanceTime()) - .build() - ).toList(); + .attendanceId(sessionAttendee.getAttendanceId()) + .name(sessionAttendee.getAttendeeName()) + .note(sessionAttendee.getAttendeeNote()) + .attendanceStatus(sessionAttendee.getAttendanceStatus()) + .attendanceTime(sessionAttendee.getAttendanceTime()) + .build() + ).toList(); } @Transactional(readOnly = true) - public List getClassAttendeesIfExistsOrEmpty(Long courseId){ + public List getClassAttendeesIfExistsOrEmpty(Long courseId) { List classAttendancesInfos = attendeeRepository.getClassAttendancesInfo(courseId); - if(classAttendancesInfos == null || classAttendancesInfos.isEmpty()) + if (classAttendancesInfos == null || classAttendancesInfos.isEmpty()) { throw new ClassAttendeesEmptyException(); + } - return classAttendancesInfos.stream().map( classAttendancesInfo -> ClassAttendees.builder() - .id(classAttendancesInfo.getAttendeeId()) - .name(classAttendancesInfo.getName()) - .note(classAttendancesInfo.getNote()) - .attendance(classAttendancesInfo.getAttendance()) - .absence(classAttendancesInfo.getAbsence()) - .build() - ).toList(); + return classAttendancesInfos.stream().map(classAttendancesInfo -> ClassAttendees.builder() + .id(classAttendancesInfo.getAttendeeId()) + .name(classAttendancesInfo.getName()) + .note(classAttendancesInfo.getNote()) + .attendance(classAttendancesInfo.getAttendance()) + .absence(classAttendancesInfo.getAbsence()) + .build() + ).toList(); } @Transactional(readOnly = true) - public int getAllByCourseId(Long courseId){ + public int getAllByCourseId(Long courseId) { return attendeeRepository.findAttendeesByCourse_Id(courseId).size(); } @Transactional(readOnly = true) - public AttendeeDetailDto getAttendanceCount(Long attendeeId){ + public AttendeeDetailDto getAttendanceCount(Long attendeeId) { Attendee attendee = attendeeRepository.findById(attendeeId) .orElseThrow(() -> new IllegalArgumentException("참여자가 존재하지 않습니다.")); @@ -185,10 +188,10 @@ public AttendeeDetailDto getAttendanceCount(Long attendeeId){ int attendance = 0; int absence = 0; - for(AttendeeAttendDetailInfo attendDetailInfo : attendanceInfoByAttendeeId){ - if(attendDetailInfo.getAttendanceStatus()){ + for (AttendeeAttendDetailInfo attendDetailInfo : attendanceInfoByAttendeeId) { + if (attendDetailInfo.getAttendanceStatus()) { attendance++; - }else{ + } else { absence++; } } @@ -202,19 +205,19 @@ public AttendeeDetailDto getAttendanceCount(Long attendeeId){ } @Override - public void updateAll(Long courseId, List updatedAttendees){ + public void updateAll(Long courseId, List updatedAttendees) { throwIfAttendeesNameAndNoteNotUnique(updatedAttendees, courseId); updatedAttendees.stream() - .map(attendee -> - Attendee.builder() - .id(attendee.getId()) - .course(Course.builder().id(courseId).build()) - .name(attendee.getName()) - .note(attendee.getNote()) - .build()) - .forEach(attendeeRepository::save); + .map(attendee -> + Attendee.builder() + .id(attendee.getId()) + .course(Course.builder().id(courseId).build()) + .name(attendee.getName()) + .note(attendee.getNote()) + .build()) + .forEach(attendeeRepository::save); } diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/query/AttendeeQueryService.java b/src/main/java/com/waruru/areyouhere/attendee/service/query/AttendeeQueryService.java index de92608..b7bc52b 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/query/AttendeeQueryService.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/query/AttendeeQueryService.java @@ -1,6 +1,5 @@ package com.waruru.areyouhere.attendee.service.query; -import com.waruru.areyouhere.attendance.service.dto.AttendanceCount; import com.waruru.areyouhere.attendee.service.dto.AttendeeDetailDto; import com.waruru.areyouhere.attendee.service.dto.ClassAttendees; import com.waruru.areyouhere.attendee.service.dto.DuplicateAttendees; diff --git a/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java b/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java index aa85db3..65f71b2 100644 --- a/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java +++ b/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java @@ -35,7 +35,8 @@ ResponseEntity getCourse(@PathVariable Long courseId) { public ResponseEntity createCourse( @Login Manager manager, @RequestBody CourseCreationRequest request) { - courseService.create(manager.getId(), request.getName(), request.getDescription(), request.getAttendees(), request.isOnlyListNameAllowed()); + courseService.create(manager.getId(), request.getName(), request.getDescription(), request.getAttendees(), + request.isOnlyListNameAllowed()); return ResponseEntity.ok().build(); } @@ -52,14 +53,15 @@ public ResponseEntity getAllCourses(@Login Manager manager) { @PutMapping("/{courseId}") public ResponseEntity updateCourse(@Login Manager manager, @PathVariable Long courseId, @RequestBody CourseUpdateRequest request) { - courseService.update(manager.getId(), courseId, request.getName(), request.getDescription(), request.isOnlyListNameAllowed()); + courseService.update(manager.getId(), courseId, request.getName(), request.getDescription(), + request.isOnlyListNameAllowed()); return ResponseEntity.ok().build(); } @LoginRequired @DeleteMapping("/{courseId}") public ResponseEntity deleteCourse(@Login Manager manager - , @PathVariable Long courseId) { + , @PathVariable Long courseId) { courseService.delete(manager.getId(), courseId); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/waruru/areyouhere/course/service/CourseService.java b/src/main/java/com/waruru/areyouhere/course/service/CourseService.java index 8087ad7..ff70635 100644 --- a/src/main/java/com/waruru/areyouhere/course/service/CourseService.java +++ b/src/main/java/com/waruru/areyouhere/course/service/CourseService.java @@ -9,9 +9,13 @@ @RestController public interface CourseService { - void create(Long managerId, String name, String description, List attendees, boolean onlyListNameAllowed); + void create(Long managerId, String name, String description, List attendees, + boolean onlyListNameAllowed); + List getAll(Long managerId); + void update(Long managerId, Long courseId, String name, String description, boolean onlyListNameAllowed); + void delete(Long managerId, Long courseId); public Course get(Long courseId); diff --git a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java index d304604..f7318d2 100644 --- a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java @@ -39,8 +39,10 @@ public class CourseServiceImpl implements CourseService { @Override - public void create(Long managerId, String name, String description, List attendees, boolean onlyListNameAllowed) { - Manager manager = managerRepository.findManagerById(managerId).orElseThrow(() -> new IllegalArgumentException("Manager not found")); + public void create(Long managerId, String name, String description, List attendees, + boolean onlyListNameAllowed) { + Manager manager = managerRepository.findManagerById(managerId) + .orElseThrow(() -> new IllegalArgumentException("Manager not found")); Course course = Course.builder() .manager(manager) @@ -52,8 +54,8 @@ public void create(Long managerId, String name, String description, List attendeesToSave = new ArrayList<>(); - if(!isAttendeesUnique(attendees.stream().map(attendeeData -> attendeeData.getName() - + (attendeeData.getNote() == null ? "": attendeeData.getNote())).toList())) { + if (!isAttendeesUnique(attendees.stream().map(attendeeData -> attendeeData.getName() + + (attendeeData.getNote() == null ? "" : attendeeData.getNote())).toList())) { throw new AttendeesNotUniqueException(); } @@ -75,7 +77,8 @@ public List getAll(Long managerId) { List eachClassAttendeeCountInfos = attendeeRepository.countAttendeesEachCourseByManagerId( managerId); Map courseAttendeeCountMap = eachClassAttendeeCountInfos.stream() - .collect(Collectors.toMap(EachClassAttendeeCountInfo::getCourseId, EachClassAttendeeCountInfo::getAttendeeCnt)); + .collect(Collectors.toMap(EachClassAttendeeCountInfo::getCourseId, + EachClassAttendeeCountInfo::getAttendeeCnt)); return courses.stream() .map(course -> CourseData.builder() diff --git a/src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java b/src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java index 573cabd..5077ee0 100644 --- a/src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java +++ b/src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java @@ -6,9 +6,4 @@ public interface AuthCodeRedisRepository extends CrudRepository{ - public Optional findAuthCodeByAuthCode(String authCode); - - public void deleteAuthCodeByAuthCode(String authCode); - - } diff --git a/src/main/java/com/waruru/areyouhere/session/service/SessionService.java b/src/main/java/com/waruru/areyouhere/session/service/SessionService.java index bf39ed9..8169283 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/SessionService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/SessionService.java @@ -11,6 +11,7 @@ public interface SessionService { public void create(Long courseId, String sessionName); public CurrentSessionDto getCurrentSessionInfo(Long courseId); + public List getRecentFive(Long courseId); public List getAll(Long courseId); diff --git a/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java index 0acb86a..9206f9c 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java @@ -35,7 +35,7 @@ public class SessionServiceImpl implements SessionService { private final SessionIdRedisRepository sessionIdRedisRepository; private final AttendanceRepository attendanceRepository; - public void create(Long courseId, String sessionName){ + public void create(Long courseId, String sessionName) { // TODO : exception 수정 Course course = courseRepository.findById(courseId) .orElseThrow(SessionIdNotFoundException::new); @@ -49,22 +49,23 @@ public void create(Long courseId, String sessionName){ } @Override - public void delete(List sessionIds){ + public void delete(List sessionIds) { sessionIds.forEach(sessionId -> { attendanceRepository.deleteAllBySessionId(sessionId); sessionRepository.findById(sessionId).orElseThrow(CurrentSessionNotFoundException::new); }); sessionRepository.deleteAllByIds(sessionIds); } + // TODO : 리팩토링 노타임.. @Transactional(readOnly = true) @Override - public CurrentSessionDto getCurrentSessionInfo(Long courseId){ + public CurrentSessionDto getCurrentSessionInfo(Long courseId) { Session mostRecentSession = sessionRepository .findMostRecentSessionByCourseId(courseId) .orElseThrow(CurrentSessionNotFoundException::new); // 제일 최근 세션이 이미 출석 체크가 끝났는지 - if(mostRecentSession.isDeactivated()){ + if (mostRecentSession.isDeactivated()) { throw new CurrentSessionDeactivatedException(); } // 제일 최근 세션이 출석 코드를 만들지 않았는지 @@ -72,13 +73,13 @@ public CurrentSessionDto getCurrentSessionInfo(Long courseId){ .findById(mostRecentSession.getId()) .orElse(null); - if(sessionId == null){ - return CurrentSessionDto.builder() - .authCode(null) - .sessionTime(null) - .sessionName(mostRecentSession.getName()) - .id(mostRecentSession.getId()) - .build(); + if (sessionId == null) { + return CurrentSessionDto.builder() + .authCode(null) + .sessionTime(null) + .sessionName(mostRecentSession.getName()) + .id(mostRecentSession.getId()) + .build(); } // 제일 최근 세션이 출석 코드를 만들었다면. // warning! 널 익셉션이 발생한다면 authCode를 redis에 삽입하는 과정에서 어느 쪽이 빠져있는 것이다. @@ -97,24 +98,24 @@ public CurrentSessionDto getCurrentSessionInfo(Long courseId){ @Transactional(readOnly = true) @Override - public List getRecentFive(Long courseId){ + public List getRecentFive(Long courseId) { List recentFiveSessions = sessionRepository.findTOP6BySessionByCourseId(courseId); - if(recentFiveSessions == null || recentFiveSessions.isEmpty()){ + if (recentFiveSessions == null || recentFiveSessions.isEmpty()) { return Collections.emptyList(); } - if(!recentFiveSessions.get(0).isDeactivated()){ + if (!recentFiveSessions.get(0).isDeactivated()) { recentFiveSessions.remove(0); - }else{ - if(recentFiveSessions.size() > 5){ + } else { + if (recentFiveSessions.size() > 5) { recentFiveSessions.remove(5); } } List list = new ArrayList<>(); for (Session recentFiveSession : recentFiveSessions) { SessionInfo sessionWithAttendance = sessionRepository.findSessionWithAttendance( - recentFiveSession.getId()) + recentFiveSession.getId()) .orElseThrow(SessionIdNotFoundException::new); list.add(SessionAttendanceInfo.builder() @@ -131,7 +132,7 @@ public List getRecentFive(Long courseId){ @Transactional(readOnly = true) @Override - public List getAll(Long courseId){ + public List getAll(Long courseId) { List allSessions = sessionRepository.findSessionsWithAttendance(courseId); return allSessions == null || allSessions.isEmpty() ? Collections.emptyList() @@ -142,12 +143,12 @@ public List getAll(Long courseId){ .attendee(allSession.getattendee()) .absentee(allSession.getabsentee()) .build() - ).toList(); + ).toList(); } @Transactional(readOnly = true) @Override - public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId){ + public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId) { SessionInfo sessionWithAttendance = sessionRepository .findSessionWithAttendance(sessionId) .orElseThrow(SessionIdNotFoundException::new); @@ -164,10 +165,10 @@ public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId){ @Transactional(readOnly = true) @Override - public void checkNotDeactivated(Long sessionId){ + public void checkNotDeactivated(Long sessionId) { Session session = sessionRepository.findById(sessionId) .orElseThrow(SessionIdNotFoundException::new); - if(session.isDeactivated()){ + if (session.isDeactivated()) { throw new CurrentSessionDeactivatedException(); } } @@ -180,14 +181,14 @@ public Session get(Long sessionId) { } @Override - public void deactivate(Long sessionId){ + public void deactivate(Long sessionId) { Session session = sessionRepository.findById(sessionId) .orElseThrow(SessionIdNotFoundException::new); session.setDeactivated(true); sessionRepository.save(session); } - - public void setStartTime(Long sessionId, LocalDateTime currentTime){ + + public void setStartTime(Long sessionId, LocalDateTime currentTime) { Session session = sessionRepository.findById(sessionId) .orElseThrow(SessionIdNotFoundException::new); session.setAuthCodeCreatedAt(currentTime); diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java index ed56023..60bbbf1 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java @@ -6,8 +6,11 @@ public interface SessionCommandService { public void create(Long courseId, String sessionName); + public void delete(List sessionIds); + public void deactivate(Long sessionId); + public void setStartTime(Long sessionId, LocalDateTime currentTime); public void updateAll(List sessions); diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index 847f77c..47bd891 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -21,23 +21,22 @@ @Service @RequiredArgsConstructor @Transactional -public class SessionCommandServiceImpl implements SessionCommandService{ +public class SessionCommandServiceImpl implements SessionCommandService { private final SessionRepository sessionRepository; private final CourseRepository courseRepository; private final AttendanceRepository attendanceRepository; private final AttendeeRepository attendeeRepository; - public void create(Long courseId, String sessionName){ + + public void create(Long courseId, String sessionName) { // TODO : exception 수정 Course course = courseRepository.findById(courseId) .orElseThrow(CourseNotFoundException::new); - if(attendeeRepository.findAttendeesByCourse_Id(courseId).isEmpty()){ + if (attendeeRepository.findAttendeesByCourse_Id(courseId).isEmpty()) { throw new AttendeeNotFoundException(); } - - Session session = Session.builder() .name(sessionName) .course(course) @@ -47,7 +46,7 @@ public void create(Long courseId, String sessionName){ } @Override - public void delete(List sessionIds){ + public void delete(List sessionIds) { sessionIds.forEach(sessionId -> { attendanceRepository.deleteAllBySessionId(sessionId); sessionRepository.findById(sessionId).orElseThrow(CurrentSessionNotFoundException::new); @@ -56,7 +55,7 @@ public void delete(List sessionIds){ } @Override - public void deactivate(Long sessionId){ + public void deactivate(Long sessionId) { Session session = sessionRepository.findById(sessionId) .orElseThrow(SessionIdNotFoundException::new); session.setDeactivated(true); @@ -64,7 +63,7 @@ public void deactivate(Long sessionId){ } @Override - public void setStartTime(Long sessionId, LocalDateTime currentTime){ + public void setStartTime(Long sessionId, LocalDateTime currentTime) { Session session = sessionRepository.findById(sessionId) .orElseThrow(SessionIdNotFoundException::new); session.setAuthCodeCreatedAt(currentTime); @@ -72,7 +71,7 @@ public void setStartTime(Long sessionId, LocalDateTime currentTime){ } @Override - public void updateAll(List sessions){ + public void updateAll(List sessions) { sessions.forEach(session -> { sessionRepository.setSessionNameById(session.getName(), session.getId()); }); diff --git a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryService.java b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryService.java index a005b08..07a7c60 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryService.java @@ -7,9 +7,14 @@ public interface SessionQueryService { public CurrentSessionDto getCurrentSessionInfo(Long courseId); + public List getRecentFive(Long courseId); + public List getAll(Long courseId); + public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId); + public void checkNotDeactivated(Long sessionId); + public Session get(Long sessionId); } diff --git a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java index 6223374..7dbdfa2 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java @@ -24,14 +24,14 @@ @Service @RequiredArgsConstructor @Transactional(readOnly = true) -public class SessionQueryServiceImpl implements SessionQueryService{ +public class SessionQueryServiceImpl implements SessionQueryService { private final SessionRepository sessionRepository; private final AuthCodeRedisRepository authCodeRedisRepository; private final SessionIdRedisRepository sessionIdRedisRepository; @Override - public CurrentSessionDto getCurrentSessionInfo(Long courseId){ + public CurrentSessionDto getCurrentSessionInfo(Long courseId) { Session mostRecentSession = sessionRepository .findMostRecentSessionByCourseId(courseId) .orElseThrow(CurrentSessionNotFoundException::new); @@ -40,7 +40,8 @@ public CurrentSessionDto getCurrentSessionInfo(Long courseId){ throwIfSessionDeactivated(mostRecentSession); // 제일 최근 세션이 출석 코드를 만들지 않았는지 - CurrentSessionAttendanceInfo currentSessionAttendanceInfo = getAuthCodeIfExistsOrEmptyAuthCode(mostRecentSession.getId()); + CurrentSessionAttendanceInfo currentSessionAttendanceInfo = getAuthCodeIfExistsOrEmptyAuthCode( + mostRecentSession.getId()); return CurrentSessionDto.builder() .authCode(currentSessionAttendanceInfo.getAuthCode()) @@ -51,19 +52,16 @@ public CurrentSessionDto getCurrentSessionInfo(Long courseId){ } - - @Override - public List getRecentFive(Long courseId){ + public List getRecentFive(Long courseId) { List recentSessions = getRecentSessions(courseId); removeExtraSession(recentSessions); return getSessionAttendanceInfoList(recentSessions); } - @Override - public List getAll(Long courseId){ + public List getAll(Long courseId) { List allSessions = sessionRepository.findSessionsWithAttendance(courseId); return allSessions == null || allSessions.isEmpty() @@ -79,7 +77,7 @@ public List getAll(Long courseId){ } @Override - public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId){ + public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId) { SessionInfo sessionWithAttendance = sessionRepository .findSessionWithAttendance(sessionId) .orElseThrow(SessionIdNotFoundException::new); @@ -95,7 +93,7 @@ public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId){ } @Override - public void checkNotDeactivated(Long sessionId){ + public void checkNotDeactivated(Long sessionId) { Session session = sessionRepository.findById(sessionId) .orElseThrow(SessionIdNotFoundException::new); throwIfSessionDeactivated(session); @@ -108,12 +106,12 @@ public Session get(Long sessionId) { } private void throwIfSessionDeactivated(Session mostRecentSession) { - if(mostRecentSession.isDeactivated()){ + if (mostRecentSession.isDeactivated()) { throw new CurrentSessionDeactivatedException(); } } - private CurrentSessionAttendanceInfo getAuthCodeIfExistsOrEmptyAuthCode(Long sessionId){ + private CurrentSessionAttendanceInfo getAuthCodeIfExistsOrEmptyAuthCode(Long sessionId) { SessionId session = sessionIdRedisRepository .findById(sessionId) .orElse(null); @@ -134,17 +132,18 @@ private List getRecentSessions(Long courseId) { } private void removeExtraSession(List recentFiveSessions) { - if(recentFiveSessions.isEmpty()){ + if (recentFiveSessions.isEmpty()) { return; } - if(!recentFiveSessions.get(0).isDeactivated()){ + if (!recentFiveSessions.get(0).isDeactivated()) { recentFiveSessions.remove(0); - }else if(recentFiveSessions.size() > 5){ + } else if (recentFiveSessions.size() > 5) { recentFiveSessions.remove(5); } } + //FIXME : 404 발생 private List getSessionAttendanceInfoList(List recentFiveSessions) { return recentFiveSessions.stream() .map(Session::getId) From bbc0a4b60d4862f13e967e4920e2e33fbded18af Mon Sep 17 00:00:00 2001 From: SHEOM Date: Tue, 9 Apr 2024 19:31:25 +0900 Subject: [PATCH 07/19] =?UTF-8?q?Fix/redis:=20=EC=93=B0=EA=B8=B0=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EC=9D=B4=20Redis=EC=97=90=20=EB=8F=99?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20(#46)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ActiveSessionService.java} | 20 ++++- .../ActiveSessionServiceImpl.java} | 84 +++++++++++++++---- .../active/domain/entity/CourseId.java | 28 +++++++ .../entity/CurrentSessionAttendanceInfo.java | 29 ++++++- .../domain/entity/SessionId.java | 3 +- .../repository/AttendanceRedisRepository.java | 6 +- .../repository/AuthCodeRedisRepository.java | 9 ++ .../repository/CourseIdRedisRepository.java | 7 ++ .../repository/SessionIdRedisRepository.java | 4 +- .../controller/AttendanceController.java | 2 +- .../controller/AuthCodeController.java | 10 +-- .../repository/AttendanceRepository.java | 2 +- .../entity => dto}/AttendeeRedisData.java | 2 +- .../service/AttendanceServiceImpl.java | 24 +++--- .../dto/CurrentSessionAttendeeAttendance.java | 2 +- .../{ => rdb}/AttendanceRDBService.java | 2 +- .../{ => rdb}/AttendanceRDBServiceImpl.java | 2 +- .../advice/AttendeeExceptionAdvice.java | 7 ++ .../controller/AttendeeController.java | 1 - .../domain/repository/AttendeeRepository.java | 2 +- .../attendee/service/AttendeeServiceImpl.java | 1 - .../command/AttendeeCommandServiceImpl.java | 21 ++++- .../course/advice/CourseExceptionAdvice.java | 7 ++ .../CourseActivatedSessionException.java | 15 ++++ .../course/service/CourseServiceImpl.java | 9 ++ .../advice/SessionExceptionAdvice.java | 7 ++ .../session/controller/SessionController.java | 2 +- .../repository/AuthCodeRedisRepository.java | 9 -- .../ActivatedSessionExistsException.java | 14 ++++ .../session/service/SessionServiceImpl.java | 8 +- .../command/SessionCommandService.java | 2 +- .../command/SessionCommandServiceImpl.java | 12 ++- .../query/SessionQueryServiceImpl.java | 9 +- 33 files changed, 283 insertions(+), 79 deletions(-) rename src/main/java/com/waruru/areyouhere/{attendance/service/AttendanceRedisService.java => active/ActiveSessionService.java} (68%) rename src/main/java/com/waruru/areyouhere/{attendance/service/AttendanceRedisServiceImpl.java => active/ActiveSessionServiceImpl.java} (72%) create mode 100644 src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java rename src/main/java/com/waruru/areyouhere/{attendance => active}/domain/entity/CurrentSessionAttendanceInfo.java (64%) rename src/main/java/com/waruru/areyouhere/{session => active}/domain/entity/SessionId.java (92%) rename src/main/java/com/waruru/areyouhere/{attendance => active}/domain/repository/AttendanceRedisRepository.java (81%) create mode 100644 src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java create mode 100644 src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java rename src/main/java/com/waruru/areyouhere/{session => active}/domain/repository/SessionIdRedisRepository.java (55%) rename src/main/java/com/waruru/areyouhere/attendance/{domain/entity => dto}/AttendeeRedisData.java (95%) rename src/main/java/com/waruru/areyouhere/attendance/service/{ => rdb}/AttendanceRDBService.java (89%) rename src/main/java/com/waruru/areyouhere/attendance/service/{ => rdb}/AttendanceRDBServiceImpl.java (98%) create mode 100644 src/main/java/com/waruru/areyouhere/course/exception/CourseActivatedSessionException.java delete mode 100644 src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java create mode 100644 src/main/java/com/waruru/areyouhere/session/exception/ActivatedSessionExistsException.java diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisService.java b/src/main/java/com/waruru/areyouhere/active/ActiveSessionService.java similarity index 68% rename from src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisService.java rename to src/main/java/com/waruru/areyouhere/active/ActiveSessionService.java index 5f43f1f..fb365bf 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisService.java +++ b/src/main/java/com/waruru/areyouhere/active/ActiveSessionService.java @@ -1,8 +1,9 @@ -package com.waruru.areyouhere.attendance.service; +package com.waruru.areyouhere.active; -import com.waruru.areyouhere.attendance.domain.entity.AttendeeRedisData; -import com.waruru.areyouhere.attendance.domain.entity.CurrentSessionAttendanceInfo; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; +import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.session.domain.entity.Session; @@ -10,7 +11,7 @@ import java.time.LocalDateTime; import java.util.List; -public interface AttendanceRedisService { +public interface ActiveSessionService { public List getNameSakeInfos(String authCode, String attendeeName); @@ -35,5 +36,16 @@ public AttendeeRedisData findByNameIfNotDuplicatedOrId(String attendeeName, Long public int getAttendCount(String authCode); + public void updateCourseName(Long courseId, String courseName); + + public void updateSessionName(Long courseId, String sessionName); + + public void updateAttendees(Long courseId, List attendees); + + + public boolean isSessionActivatedByCourseId(Long courseId); + + public boolean isSessionActivatedBySessionId(Long sessionId); + } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisServiceImpl.java b/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java similarity index 72% rename from src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisServiceImpl.java rename to src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java index 882876c..a23cbe2 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRedisServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java @@ -1,7 +1,9 @@ -package com.waruru.areyouhere.attendance.service; +package com.waruru.areyouhere.active; -import com.waruru.areyouhere.attendance.domain.entity.AttendeeRedisData; -import com.waruru.areyouhere.attendance.domain.repository.AttendanceRedisRepository; +import com.waruru.areyouhere.active.domain.entity.CourseId; +import com.waruru.areyouhere.active.domain.repository.CourseIdRedisRepository; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; +import com.waruru.areyouhere.active.domain.repository.AttendanceRedisRepository; import com.waruru.areyouhere.attendance.exception.AlreadyAttendException; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import com.waruru.areyouhere.attendee.domain.entity.Attendee; @@ -9,11 +11,11 @@ import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; import com.waruru.areyouhere.common.utils.RandomIdentifierGenerator; import com.waruru.areyouhere.course.domain.entity.Course; -import com.waruru.areyouhere.attendance.domain.entity.CurrentSessionAttendanceInfo; +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.session.domain.entity.SessionId; -import com.waruru.areyouhere.session.domain.repository.AuthCodeRedisRepository; -import com.waruru.areyouhere.session.domain.repository.SessionIdRedisRepository; +import com.waruru.areyouhere.active.domain.entity.SessionId; +import com.waruru.areyouhere.active.domain.repository.AuthCodeRedisRepository; +import com.waruru.areyouhere.active.domain.repository.SessionIdRedisRepository; import com.waruru.areyouhere.attendance.exception.AuthCodeNotFoundException; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; import com.waruru.areyouhere.session.service.dto.AuthCodeInfo; @@ -24,19 +26,19 @@ import java.util.Set; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; //TODO : 일관성있는 메소드명 @Service @RequiredArgsConstructor -public class AttendanceRedisServiceImpl implements AttendanceRedisService { +public class ActiveSessionServiceImpl implements ActiveSessionService { private final AuthCodeRedisRepository authCodeRedisRepository; private final SessionIdRedisRepository sessionIdRedisRepository; private final AttendanceRedisRepository attendanceRedisRepository; private final AttendeeRepository attendeeRepository; private final RandomIdentifierGenerator randomIdentifierGenerator; + private final CourseIdRedisRepository courseIdRedisRepository; @Override @@ -75,11 +77,6 @@ public AuthCodeInfo isAttendPossible(String authCode, String attendeeName, Long .build(); } - public CurrentSessionAttendanceInfo getSessionAttendanceInfoOrThrow(String authCode) { - return authCodeRedisRepository - .findById(authCode) - .orElseThrow(AuthCodeNotFoundException::new); - } @Override public void setAttendInRedis(String authCode, AttendeeRedisData attendeeInfo) { @@ -95,6 +92,7 @@ public String createAuthCode(Course course, Session session, LocalDateTime curre CurrentSessionAttendanceInfo currentSessionAttendanceInfo = CurrentSessionAttendanceInfo.builder() .sessionId(session.getId()) + .courseId(course.getId()) .authCode(generatedAuthCode) .attendees(attendeesByCourseId) .sessionName(session.getName()) @@ -110,6 +108,13 @@ public String createAuthCode(Course course, Session session, LocalDateTime curre sessionIdRedisRepository.save(newsessionId); + CourseId courseId = CourseId.builder() + .authCode(currentSessionAttendanceInfo.getAuthCode()) + .courseId(course.getId()) + .build(); + + courseIdRedisRepository.save(courseId); + return generatedAuthCode; } @@ -121,9 +126,9 @@ public void deactivate(String authCode) { authCode); authCodeRedisRepository.delete(authCodeByCurrentSessionAttendanceInfo); + courseIdRedisRepository.deleteById(authCodeByCurrentSessionAttendanceInfo.getCourseId()); sessionIdRedisRepository.deleteById(authCodeByCurrentSessionAttendanceInfo.getSessionId()); - attendanceRedisRepository.deleteAllAttendanceInSession(authCode); - + attendanceRedisRepository.deleteAllAttendanceInSession(authCodeByCurrentSessionAttendanceInfo.getAuthCode()); } public CurrentSessionAttendeeAttendance getCurrentSessionAttendees(String authCode) { @@ -175,10 +180,57 @@ public int getTotalAttendees(String authCode) { .orElseThrow(AuthCodeNotFoundException::new).getAttendees().size(); } + public void updateCourseName(Long courseId, String courseName) { + getCurrentSessionAttendanceInfoByCourseId(courseId) + .ifPresent(currentSessionAttendanceInfoData -> { + currentSessionAttendanceInfoData.setCourseName(courseName); + authCodeRedisRepository.save(currentSessionAttendanceInfoData); + }); + } + + public void updateSessionName(Long courseId, String sessionName) { + getCurrentSessionAttendanceInfoByCourseId(courseId) + .ifPresent(currentSessionAttendanceInfoData -> { + currentSessionAttendanceInfoData.setSessionName(sessionName); + authCodeRedisRepository.save(currentSessionAttendanceInfoData); + }); + } + + public void updateAttendees(Long courseId, List attendees) { + getCurrentSessionAttendanceInfoByCourseId(courseId) + .ifPresent(currentSessionAttendanceInfoData -> { + currentSessionAttendanceInfoData.updateAttendees(attendees); + authCodeRedisRepository.save(currentSessionAttendanceInfoData); + }); + } + + + public Optional getCurrentSessionAttendanceInfoByCourseId(Long courseId) { + return courseIdRedisRepository.findById(courseId) + .flatMap(findCourseId -> authCodeRedisRepository.findById(findCourseId.getAuthCode())); + } + + public CurrentSessionAttendanceInfo getSessionAttendanceInfoOrThrow(String authCode) { + return authCodeRedisRepository + .findById(authCode) + .orElseThrow(AuthCodeNotFoundException::new); + } + + public int getAttendCount(String authCode) { return attendanceRedisRepository.getAttendees(authCode).size(); } + public boolean isSessionActivatedByCourseId(Long courseId){ + return courseIdRedisRepository.findById(courseId).isPresent(); + } + + public boolean isSessionActivatedBySessionId(Long sessionId){ + return sessionIdRedisRepository.findById(sessionId).isPresent(); + } + + + private String generateAuthCode() { String generatedAuthCode = ""; while (true) { diff --git a/src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java b/src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java new file mode 100644 index 0000000..197e0ef --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java @@ -0,0 +1,28 @@ +package com.waruru.areyouhere.active.domain.entity; + + +import jakarta.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; + +@Getter +@RedisHash(value = "course_id") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class CourseId { + @Id + @NotNull + private long courseId; + + @NotNull + private String authCode; + + @Builder + public CourseId(long courseId, String authCode) { + this.courseId = courseId; + this.authCode = authCode; + } +} diff --git a/src/main/java/com/waruru/areyouhere/attendance/domain/entity/CurrentSessionAttendanceInfo.java b/src/main/java/com/waruru/areyouhere/active/domain/entity/CurrentSessionAttendanceInfo.java similarity index 64% rename from src/main/java/com/waruru/areyouhere/attendance/domain/entity/CurrentSessionAttendanceInfo.java rename to src/main/java/com/waruru/areyouhere/active/domain/entity/CurrentSessionAttendanceInfo.java index fc38552..05b0166 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/domain/entity/CurrentSessionAttendanceInfo.java +++ b/src/main/java/com/waruru/areyouhere/active/domain/entity/CurrentSessionAttendanceInfo.java @@ -1,17 +1,19 @@ -package com.waruru.areyouhere.attendance.domain.entity; +package com.waruru.areyouhere.active.domain.entity; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.cglib.core.Local; +import lombok.Setter; import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; @@ -26,20 +28,26 @@ public class CurrentSessionAttendanceInfo { @NotNull private long sessionId; + @NotNull + private long courseId; + private List attendees; @NotNull + @Setter private String courseName; @NotNull + @Setter private String sessionName; private LocalDateTime createdAt; @Builder - public CurrentSessionAttendanceInfo(String authCode, long sessionId, List attendees, String courseName, String sessionName) { + public CurrentSessionAttendanceInfo(String authCode, long sessionId, long courseId, List attendees, String courseName, String sessionName) { this.authCode = authCode; this.sessionId = sessionId; + this.courseId = courseId; this.attendees = Optional.ofNullable(attendees) .orElse(Collections.emptyList()) .stream() @@ -48,9 +56,22 @@ public CurrentSessionAttendanceInfo(String authCode, long sessionId, List attendees){ + this.attendees = Optional.ofNullable(attendees) + .orElse(Collections.emptyList()) + .stream() + .map(attendee -> AttendeeRedisData.builder() + .id(attendee.getId()) + .name(attendee.getName()) + .note(attendee.getNote()) + .build()) + .toList(); + } + } diff --git a/src/main/java/com/waruru/areyouhere/session/domain/entity/SessionId.java b/src/main/java/com/waruru/areyouhere/active/domain/entity/SessionId.java similarity index 92% rename from src/main/java/com/waruru/areyouhere/session/domain/entity/SessionId.java rename to src/main/java/com/waruru/areyouhere/active/domain/entity/SessionId.java index 9c13c41..8b88405 100644 --- a/src/main/java/com/waruru/areyouhere/session/domain/entity/SessionId.java +++ b/src/main/java/com/waruru/areyouhere/active/domain/entity/SessionId.java @@ -1,4 +1,5 @@ -package com.waruru.areyouhere.session.domain.entity; +package com.waruru.areyouhere.active.domain.entity; + import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/AttendanceRedisRepository.java similarity index 81% rename from src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceRedisRepository.java rename to src/main/java/com/waruru/areyouhere/active/domain/repository/AttendanceRedisRepository.java index c4e6f76..d2c364b 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceRedisRepository.java +++ b/src/main/java/com/waruru/areyouhere/active/domain/repository/AttendanceRedisRepository.java @@ -1,12 +1,10 @@ -package com.waruru.areyouhere.attendance.domain.repository; +package com.waruru.areyouhere.active.domain.repository; -import com.waruru.areyouhere.attendance.domain.entity.AttendeeRedisData; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; import java.util.Set; import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Repository; @Component @RequiredArgsConstructor diff --git a/src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java new file mode 100644 index 0000000..47ff117 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java @@ -0,0 +1,9 @@ +package com.waruru.areyouhere.active.domain.repository; + +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; +import org.springframework.data.repository.CrudRepository; + + +public interface AuthCodeRedisRepository extends CrudRepository{ + +} diff --git a/src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java new file mode 100644 index 0000000..473d908 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java @@ -0,0 +1,7 @@ +package com.waruru.areyouhere.active.domain.repository; + +import com.waruru.areyouhere.active.domain.entity.CourseId; +import org.springframework.data.repository.CrudRepository; + +public interface CourseIdRedisRepository extends CrudRepository { +} diff --git a/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionIdRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/SessionIdRedisRepository.java similarity index 55% rename from src/main/java/com/waruru/areyouhere/session/domain/repository/SessionIdRedisRepository.java rename to src/main/java/com/waruru/areyouhere/active/domain/repository/SessionIdRedisRepository.java index b7382e9..ea201e4 100644 --- a/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionIdRedisRepository.java +++ b/src/main/java/com/waruru/areyouhere/active/domain/repository/SessionIdRedisRepository.java @@ -1,6 +1,6 @@ -package com.waruru.areyouhere.session.domain.repository; +package com.waruru.areyouhere.active.domain.repository; -import com.waruru.areyouhere.session.domain.entity.SessionId; +import com.waruru.areyouhere.active.domain.entity.SessionId; import org.springframework.data.repository.CrudRepository; public interface SessionIdRedisRepository extends CrudRepository { diff --git a/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java b/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java index e281c4d..995a32f 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java +++ b/src/main/java/com/waruru/areyouhere/attendance/controller/AttendanceController.java @@ -42,7 +42,7 @@ public class AttendanceController { private final AttendanceService attendanceService; - //FIXME: 1. 중복 인원인 경우 코드 중복이 생겨도 API 분리가 나아 보인다. 한 API에서 너무 많은 일을 하는 중이다. + // FIXME: 1. 중복 인원인 경우 코드 중복이 생겨도 API 분리가 나아 보인다. 한 API에서 너무 많은 일을 하는 중이다. // FIXME: 2. 사실상 다른 형태의 response를 억지로 하나의 controller에서 반환한다고 봐도 무방하다. -> 프론트와 합의 후 변경. @PostMapping public ResponseEntity attend(HttpServletRequest request, diff --git a/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java b/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java index 35128e0..5d7ab81 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java +++ b/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java @@ -1,13 +1,13 @@ package com.waruru.areyouhere.attendance.controller; -import com.waruru.areyouhere.attendance.service.AttendanceRDBService; +import com.waruru.areyouhere.attendance.service.rdb.AttendanceRDBService; import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.course.service.CourseService; import com.waruru.areyouhere.session.domain.entity.Session; import com.waruru.areyouhere.attendance.dto.request.AuthCodeDeactivationRequestDto; import com.waruru.areyouhere.attendance.dto.request.AuthCodeRequestDto; -import com.waruru.areyouhere.attendance.service.AttendanceRedisService; +import com.waruru.areyouhere.active.ActiveSessionService; import com.waruru.areyouhere.session.service.command.SessionCommandService; import com.waruru.areyouhere.session.service.query.SessionQueryService; import java.time.LocalDateTime; @@ -26,7 +26,7 @@ public class AuthCodeController { public static final String AUTH_CODE_API_URL = "/api/auth-code"; - private final AttendanceRedisService attendanceRedisService; + private final ActiveSessionService activeSessionService; private final AttendanceRDBService attendanceRDBService; private final SessionCommandService sessionCommandService; private final SessionQueryService sessionQueryService; @@ -41,7 +41,7 @@ public ResponseEntity create(@RequestBody AuthCodeRequestDto authCodeReq Course course = courseService.get(courseId); Session session = sessionQueryService.get(sessionId); sessionCommandService.setStartTime(sessionId, currentTime); - return ResponseEntity.ok(attendanceRedisService.createAuthCode(course, session, currentTime)); + return ResponseEntity.ok(activeSessionService.createAuthCode(course, session, currentTime)); } @PostMapping("/deactivate") @@ -54,7 +54,7 @@ public ResponseEntity deactivate( sessionQueryService.checkNotDeactivated(sessionId); sessionCommandService.deactivate(sessionId); - attendanceRedisService.deactivate(authCode); + activeSessionService.deactivate(authCode); attendanceRDBService.setAbsentAfterDeactivation(courseId, sessionId); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceRepository.java b/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceRepository.java index 74a076d..0077c27 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceRepository.java +++ b/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceRepository.java @@ -11,7 +11,7 @@ public interface AttendanceRepository extends JpaRepository{ public List findAttendancesBySession_Id(Long sessionId); - @Modifying(clearAutomatically = true) + @Modifying(clearAutomatically = true, flushAutomatically = true) @Query("delete from attendance a where a.attendee.id in :ids") public void deleteAllByAttendeeIds(@Param("ids") List ids); diff --git a/src/main/java/com/waruru/areyouhere/attendance/domain/entity/AttendeeRedisData.java b/src/main/java/com/waruru/areyouhere/attendance/dto/AttendeeRedisData.java similarity index 95% rename from src/main/java/com/waruru/areyouhere/attendance/domain/entity/AttendeeRedisData.java rename to src/main/java/com/waruru/areyouhere/attendance/dto/AttendeeRedisData.java index 6a92867..dd1d04f 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/domain/entity/AttendeeRedisData.java +++ b/src/main/java/com/waruru/areyouhere/attendance/dto/AttendeeRedisData.java @@ -1,4 +1,4 @@ -package com.waruru.areyouhere.attendance.domain.entity; +package com.waruru.areyouhere.attendance.dto; import java.util.Objects; import lombok.AccessLevel; diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java index e0f18c5..12888da 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java @@ -1,10 +1,12 @@ package com.waruru.areyouhere.attendance.service; -import com.waruru.areyouhere.attendance.domain.entity.AttendeeRedisData; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; import com.waruru.areyouhere.attendance.dto.UpdateAttendance; import com.waruru.areyouhere.attendance.dto.response.AttendResponseDto; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendCount; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; +import com.waruru.areyouhere.attendance.service.rdb.AttendanceRDBService; +import com.waruru.areyouhere.active.ActiveSessionService; import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; import com.waruru.areyouhere.session.service.dto.AuthCodeInfo; import java.time.LocalDateTime; @@ -20,13 +22,13 @@ @RequiredArgsConstructor public class AttendanceServiceImpl implements AttendanceService { private final AttendanceRDBService attendanceRDBService; - private final AttendanceRedisService attendanceRedisService; + private final ActiveSessionService activeSessionService; @Override @Transactional public AttendResponseDto attend(String attendeeName, String authCode, Long attendeeId) { LocalDateTime attendanceTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); - List nameSakeAttendees = attendanceRedisService.getNameSakeInfos(authCode, attendeeName); + List nameSakeAttendees = activeSessionService.getNameSakeInfos(authCode, attendeeName); // 동명이인 응답 if (attendeeId == null && nameSakeAttendees.size() > 1) { @@ -35,12 +37,12 @@ public AttendResponseDto attend(String attendeeName, String authCode, Long atten .build(); } - AuthCodeInfo authCodeInfo = attendanceRedisService.isAttendPossible(authCode, attendeeName, attendeeId); + AuthCodeInfo authCodeInfo = activeSessionService.isAttendPossible(authCode, attendeeName, attendeeId); attendanceRDBService.setAttend(authCodeInfo.getSessionId(), attendeeName, attendeeId); - AttendeeRedisData attendeeInSession = attendanceRedisService.findByNameIfNotDuplicatedOrId(attendeeName, + AttendeeRedisData attendeeInSession = activeSessionService.findByNameIfNotDuplicatedOrId(attendeeName, attendeeId, - attendanceRedisService.getSessionAttendanceInfoOrThrow(authCode)); - attendanceRedisService.setAttendInRedis(authCode, attendeeInSession); + activeSessionService.getSessionAttendanceInfoOrThrow(authCode)); + activeSessionService.setAttendInRedis(authCode, attendeeInSession); return AttendResponseDto.builder() .attendanceName(attendeeName) @@ -59,16 +61,16 @@ public void updateAllStatuses(Long sessionId, List updateAtten @Override @Transactional(readOnly = true) public CurrentSessionAttendCount getCurrentSessionAttendCount(Long sessionId) { - String authCode = attendanceRedisService.findAuthCodeBySessionId(sessionId); - int total = attendanceRedisService.getTotalAttendees(authCode); - int attendeeCount = attendanceRedisService.getAttendCount(authCode); + String authCode = activeSessionService.findAuthCodeBySessionId(sessionId); + int total = activeSessionService.getTotalAttendees(authCode); + int attendeeCount = activeSessionService.getAttendCount(authCode); return new CurrentSessionAttendCount(total, attendeeCount); } @Override @Transactional(readOnly = true) public CurrentSessionAttendeeAttendance getCurrentSessionAttendeesAndAbsentees(String authCode) { - return attendanceRedisService.getCurrentSessionAttendees(authCode); + return activeSessionService.getCurrentSessionAttendees(authCode); } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/dto/CurrentSessionAttendeeAttendance.java b/src/main/java/com/waruru/areyouhere/attendance/service/dto/CurrentSessionAttendeeAttendance.java index 9ef691c..11df4ce 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/dto/CurrentSessionAttendeeAttendance.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/dto/CurrentSessionAttendeeAttendance.java @@ -1,6 +1,6 @@ package com.waruru.areyouhere.attendance.service.dto; -import com.waruru.areyouhere.attendance.domain.entity.AttendeeRedisData; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; import java.util.List; import lombok.AccessLevel; import lombok.Builder; diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBService.java b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBService.java similarity index 89% rename from src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBService.java rename to src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBService.java index cbbc93f..40300f3 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBService.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBService.java @@ -1,4 +1,4 @@ -package com.waruru.areyouhere.attendance.service; +package com.waruru.areyouhere.attendance.service.rdb; import com.waruru.areyouhere.attendance.dto.UpdateAttendance; import java.util.List; diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBServiceImpl.java similarity index 98% rename from src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBServiceImpl.java rename to src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBServiceImpl.java index 403b81f..4dc701f 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceRDBServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBServiceImpl.java @@ -1,4 +1,4 @@ -package com.waruru.areyouhere.attendance.service; +package com.waruru.areyouhere.attendance.service.rdb; import com.waruru.areyouhere.attendance.domain.entity.Attendance; diff --git a/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java index 7ebbc56..2aae986 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java @@ -10,6 +10,7 @@ import com.waruru.areyouhere.attendee.exception.SessionAttendeesEmptyException; import com.waruru.areyouhere.attendee.exception.AttendeesNotUniqueException; import com.waruru.areyouhere.course.exception.CourseNotFoundException; +import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -17,6 +18,12 @@ @RestControllerAdvice("com.waruru.areyouhere.attendee") public class AttendeeExceptionAdvice { + + @ExceptionHandler(ActivatedSessionExistsException.class) + public ResponseEntity activatedSessionExistsHandler() { + return RESPONSE_CONFLICT; + } + @ExceptionHandler(CourseNotFoundException.class) public ResponseEntity courseIdNotFoundFoundHandler() { return RESPONSE_NOT_FOUND; diff --git a/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java b/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java index 7d93b8b..628f5b6 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java +++ b/src/main/java/com/waruru/areyouhere/attendee/controller/AttendeeController.java @@ -7,7 +7,6 @@ import com.waruru.areyouhere.attendee.dto.request.DeleteAttendeesRequestDto; import com.waruru.areyouhere.attendee.dto.request.DuplicateCheckAttendeesRequestDto; import com.waruru.areyouhere.attendee.dto.request.NewAttendeesRequestDto; -import com.waruru.areyouhere.attendee.service.AttendeeService; import com.waruru.areyouhere.attendee.service.dto.ClassAttendees; import com.waruru.areyouhere.attendee.service.dto.DuplicateAttendees; import com.waruru.areyouhere.attendee.service.query.AttendeeQueryService; diff --git a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java index d4ca50c..4ffb5b2 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java +++ b/src/main/java/com/waruru/areyouhere/attendee/domain/repository/AttendeeRepository.java @@ -56,7 +56,7 @@ public interface AttendeeRepository extends JpaRepository { + "GROUP BY atda.id", nativeQuery = true) public List findAttendanceInfoByAttendeeId(@Param("attendeeId") Long attendeeId); - @Modifying(clearAutomatically = true) + @Modifying(clearAutomatically = true, flushAutomatically = true) @Query("delete from attendee a where a.id in :ids") public void deleteAllByIds(@Param("ids") List ids); diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java index 2f5dd73..33bddd3 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java @@ -218,7 +218,6 @@ public void updateAll(Long courseId, List updatedAttendees) { .note(attendee.getNote()) .build()) .forEach(attendeeRepository::save); - } // TODO: Name에 index가 없다면 위에 비해 그리 빠를 지 모르겠다. diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java index c042c48..2645644 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java @@ -1,14 +1,17 @@ package com.waruru.areyouhere.attendee.service.command; +import com.waruru.areyouhere.active.ActiveSessionService; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeBatchRepository; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; +import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; import com.waruru.areyouhere.attendee.exception.AttendeesNotUniqueException; import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.course.domain.repository.CourseRepository; import com.waruru.areyouhere.course.exception.CourseNotFoundException; +import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -31,6 +34,7 @@ public class AttendeeCommandServiceImpl implements AttendeeCommandService{ private final AttendanceRepository attendanceRepository; private final AttendeeBatchRepository attendeeBatchRepository; private final CourseRepository courseRepository; + private final ActiveSessionService activeSessionService; @Override public void createAll(Long courseId, List newAttendees){ @@ -61,13 +65,13 @@ public void createAll(Long courseId, List newAttendees){ attendeeRepository.saveAll(attendeeToUpdate); attendeeBatchRepository.insertAttendeesBatch(attendeesToSave); + syncToRedis(courseId); } @Override public void updateAll(Long courseId, List updatedAttendees){ throwIfAttendeesNameAndNoteNotUnique(updatedAttendees, courseId); - updatedAttendees.stream() .map(attendee -> Attendee.builder() @@ -77,14 +81,27 @@ public void updateAll(Long courseId, List updatedAttendees){ .note(attendee.getNote()) .build()) .forEach(attendeeRepository::save); - + attendeeRepository.findAttendeesByCourse_Id(courseId); + syncToRedis(courseId); } public void deleteAll(List deleteAttendees){ + Long courseId = attendeeRepository.findById(deleteAttendees.get(0)) + .orElseThrow(() -> new AttendeeNotFoundException("Attendee not found")) + .getCourse().getId(); + if(activeSessionService.isSessionActivatedByCourseId(courseId)){ + throw new ActivatedSessionExistsException(); + } attendanceRepository.deleteAllByAttendeeIds(deleteAttendees); attendeeRepository.deleteAllByIds(deleteAttendees); } + private void syncToRedis(Long courseId){ + List attendees = attendeeRepository.findAttendeesByCourse_Id(courseId); + activeSessionService.updateAttendees(courseId, attendees); + } + + // TODO: Name에 index가 없다면 위에 비해 그리 빠를 지 모르겠다. // FIXME: Map> 같은 것 대신 그냥 class 선언해서 쓰는게 private void throwIfAttendeesNameAndNoteNotUnique(List newAttendees, Long courseId) { diff --git a/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java index 4a825b2..f78edff 100644 --- a/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java @@ -6,6 +6,7 @@ import com.waruru.areyouhere.course.exception.CourseNotFoundException; import com.waruru.areyouhere.manager.exception.ManagerNotFoundException; import com.waruru.areyouhere.course.exception.UnauthorizedManagerException; +import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -37,10 +38,16 @@ public ResponseEntity handleAttendeesNotUniqueException(AttendeesNot return RESPONSE_BAD_REQUEST; } + @ExceptionHandler(ActivatedSessionExistsException.class) + public ResponseEntity handleActivatedSessionExistsException(ActivatedSessionExistsException ex, WebRequest request) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(ex.getMessage()); + } + @ExceptionHandler(Exception.class) public ResponseEntity handleGlobalException(Exception ex, WebRequest request) { // 모든 나머지 예외들을 처리 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An unexpected error occurred"); } + } diff --git a/src/main/java/com/waruru/areyouhere/course/exception/CourseActivatedSessionException.java b/src/main/java/com/waruru/areyouhere/course/exception/CourseActivatedSessionException.java new file mode 100644 index 0000000..d1fbf97 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/course/exception/CourseActivatedSessionException.java @@ -0,0 +1,15 @@ +package com.waruru.areyouhere.course.exception; + +public class CourseActivatedSessionException extends RuntimeException{ + public CourseActivatedSessionException() { + super(); + } + + public CourseActivatedSessionException(String message) { + super(message); + } + + public CourseActivatedSessionException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java index f7318d2..2fac304 100644 --- a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java @@ -1,5 +1,6 @@ package com.waruru.areyouhere.course.service; +import com.waruru.areyouhere.active.ActiveSessionService; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeBatchRepository; @@ -10,10 +11,12 @@ import com.waruru.areyouhere.course.domain.repository.CourseRepository; import com.waruru.areyouhere.attendee.exception.AttendeesNotUniqueException; import com.waruru.areyouhere.course.dto.CourseData; +import com.waruru.areyouhere.course.exception.CourseActivatedSessionException; import com.waruru.areyouhere.manager.domain.entity.Manager; import com.waruru.areyouhere.manager.domain.repository.ManagerRepository; import com.waruru.areyouhere.session.domain.entity.Session; import com.waruru.areyouhere.session.domain.repository.SessionRepository; +import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -36,6 +39,7 @@ public class CourseServiceImpl implements CourseService { private final AttendeeRepository attendeeRepository; private final AttendanceRepository attendanceRepository; private final SessionRepository sessionRepository; + private final ActiveSessionService activeSessionService; @Override @@ -102,10 +106,15 @@ public void update(Long managerId, Long courseId, String name, String descriptio course.update(name, description, onlyListNameAllowed); courseRepository.save(course); + activeSessionService.updateCourseName(courseId, name); } @Override public void delete(Long managerId, Long courseId) { + if(activeSessionService.isSessionActivatedByCourseId(courseId)){ + throw new ActivatedSessionExistsException("Session is activated"); + } + Course course = courseRepository.findById(courseId). orElseThrow(() -> new IllegalArgumentException("Course not found")); diff --git a/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java index 41890d6..2781935 100644 --- a/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java @@ -1,11 +1,13 @@ package com.waruru.areyouhere.session.advice; import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_BAD_REQUEST; +import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_CONFLICT; import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_NOT_FOUND; import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_NO_CONTENT; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; import com.waruru.areyouhere.course.exception.CourseNotFoundException; +import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; import com.waruru.areyouhere.session.exception.CurrentSessionDeactivatedException; import com.waruru.areyouhere.session.exception.CurrentSessionNotFoundException; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; @@ -48,4 +50,9 @@ public ResponseEntity methodArgumentNotValidHandler(){ public ResponseEntity attendeeNotFoundHandler(){ return RESPONSE_BAD_REQUEST; } + + @ExceptionHandler(ActivatedSessionExistsException.class) + public ResponseEntity activatedSessionExistsHandler(){ + return RESPONSE_CONFLICT; + } } diff --git a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java index 8f7d2a0..5541a67 100644 --- a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java +++ b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java @@ -57,7 +57,7 @@ public ResponseEntity create(@RequestBody CreateSessionRequestDto cr @PostMapping("/delete") public ResponseEntity delete(@RequestBody DeleteSessionRequestDto sessionIds){ - sessionCommandService.delete(sessionIds.getSessionIds()); + sessionCommandService.deleteAll(sessionIds.getSessionIds()); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java b/src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java deleted file mode 100644 index 5077ee0..0000000 --- a/src/main/java/com/waruru/areyouhere/session/domain/repository/AuthCodeRedisRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.waruru.areyouhere.session.domain.repository; - -import com.waruru.areyouhere.attendance.domain.entity.CurrentSessionAttendanceInfo; -import java.util.Optional; -import org.springframework.data.repository.CrudRepository; - -public interface AuthCodeRedisRepository extends CrudRepository{ - -} diff --git a/src/main/java/com/waruru/areyouhere/session/exception/ActivatedSessionExistsException.java b/src/main/java/com/waruru/areyouhere/session/exception/ActivatedSessionExistsException.java new file mode 100644 index 0000000..72effc6 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/session/exception/ActivatedSessionExistsException.java @@ -0,0 +1,14 @@ +package com.waruru.areyouhere.session.exception; + +public class ActivatedSessionExistsException extends RuntimeException{ + public ActivatedSessionExistsException() { + } + + public ActivatedSessionExistsException(String message) { + super(message); + } + + public ActivatedSessionExistsException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java index 9206f9c..ea5d27d 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java @@ -3,11 +3,11 @@ import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.course.domain.repository.CourseRepository; -import com.waruru.areyouhere.attendance.domain.entity.CurrentSessionAttendanceInfo; +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.session.domain.entity.SessionId; -import com.waruru.areyouhere.session.domain.repository.AuthCodeRedisRepository; -import com.waruru.areyouhere.session.domain.repository.SessionIdRedisRepository; +import com.waruru.areyouhere.active.domain.entity.SessionId; +import com.waruru.areyouhere.active.domain.repository.AuthCodeRedisRepository; +import com.waruru.areyouhere.active.domain.repository.SessionIdRedisRepository; import com.waruru.areyouhere.session.domain.repository.SessionRepository; import com.waruru.areyouhere.session.domain.repository.dto.SessionInfo; import com.waruru.areyouhere.session.exception.CurrentSessionDeactivatedException; diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java index 60bbbf1..2c05607 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java @@ -7,7 +7,7 @@ public interface SessionCommandService { public void create(Long courseId, String sessionName); - public void delete(List sessionIds); + public void deleteAll(List sessionIds); public void deactivate(Long sessionId); diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index 47bd891..fc29989 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -1,5 +1,6 @@ package com.waruru.areyouhere.session.service.command; +import com.waruru.areyouhere.active.ActiveSessionService; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; @@ -9,6 +10,7 @@ import com.waruru.areyouhere.course.exception.CourseNotFoundException; import com.waruru.areyouhere.session.domain.entity.Session; import com.waruru.areyouhere.session.domain.repository.SessionRepository; +import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; import com.waruru.areyouhere.session.exception.CurrentSessionNotFoundException; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; import com.waruru.areyouhere.session.service.dto.UpdateSession; @@ -27,12 +29,20 @@ public class SessionCommandServiceImpl implements SessionCommandService { private final CourseRepository courseRepository; private final AttendanceRepository attendanceRepository; private final AttendeeRepository attendeeRepository; + private final ActiveSessionService activeSessionService; public void create(Long courseId, String sessionName) { // TODO : exception 수정 Course course = courseRepository.findById(courseId) .orElseThrow(CourseNotFoundException::new); + sessionRepository.findMostRecentSessionByCourseId(courseId) + .ifPresent(session -> { + if (!session.isDeactivated()) { + throw new ActivatedSessionExistsException(); + } + }); + if (attendeeRepository.findAttendeesByCourse_Id(courseId).isEmpty()) { throw new AttendeeNotFoundException(); } @@ -46,7 +56,7 @@ public void create(Long courseId, String sessionName) { } @Override - public void delete(List sessionIds) { + public void deleteAll(List sessionIds) { sessionIds.forEach(sessionId -> { attendanceRepository.deleteAllBySessionId(sessionId); sessionRepository.findById(sessionId).orElseThrow(CurrentSessionNotFoundException::new); diff --git a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java index 7dbdfa2..8cbefe7 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java @@ -1,10 +1,10 @@ package com.waruru.areyouhere.session.service.query; -import com.waruru.areyouhere.attendance.domain.entity.CurrentSessionAttendanceInfo; +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.session.domain.entity.SessionId; -import com.waruru.areyouhere.session.domain.repository.AuthCodeRedisRepository; -import com.waruru.areyouhere.session.domain.repository.SessionIdRedisRepository; +import com.waruru.areyouhere.active.domain.entity.SessionId; +import com.waruru.areyouhere.active.domain.repository.AuthCodeRedisRepository; +import com.waruru.areyouhere.active.domain.repository.SessionIdRedisRepository; import com.waruru.areyouhere.session.domain.repository.SessionRepository; import com.waruru.areyouhere.session.domain.repository.dto.SessionInfo; import com.waruru.areyouhere.session.exception.CurrentSessionDeactivatedException; @@ -12,7 +12,6 @@ import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; import com.waruru.areyouhere.session.service.dto.CurrentSessionDto; import com.waruru.areyouhere.session.service.dto.SessionAttendanceInfo; -import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.Optional; From 798c8096f5b1c8a82e9005c3d74a5e35904bc6c5 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Sat, 13 Apr 2024 18:22:57 +0900 Subject: [PATCH 08/19] Fix/Timezone: change default timezone to Asia/Seoul (#47) --- .../areyouhere/AreYouHereApplication.java | 7 +++++ .../active/ActiveSessionServiceImpl.java | 7 +++-- .../attendee/service/AttendeeService.java | 2 -- .../attendee/service/AttendeeServiceImpl.java | 27 ------------------- .../command/SessionCommandServiceImpl.java | 1 - 5 files changed, 10 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java b/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java index bf213b9..225f044 100644 --- a/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java +++ b/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java @@ -1,5 +1,7 @@ package com.waruru.areyouhere; +import jakarta.annotation.PostConstruct; +import java.util.TimeZone; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; @@ -15,4 +17,9 @@ public static void main(String[] args) { SpringApplication.run(AreYouHereApplication.class, args); } + @PostConstruct + void started(){ + TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")); + } + } diff --git a/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java index a23cbe2..2f317b2 100644 --- a/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java @@ -4,7 +4,6 @@ import com.waruru.areyouhere.active.domain.repository.CourseIdRedisRepository; import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; import com.waruru.areyouhere.active.domain.repository.AttendanceRedisRepository; -import com.waruru.areyouhere.attendance.exception.AlreadyAttendException; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; @@ -18,6 +17,7 @@ import com.waruru.areyouhere.active.domain.repository.SessionIdRedisRepository; import com.waruru.areyouhere.attendance.exception.AuthCodeNotFoundException; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; +import com.waruru.areyouhere.attendance.exception.AlreadyAttendException; import com.waruru.areyouhere.session.service.dto.AuthCodeInfo; import java.time.LocalDateTime; import java.util.LinkedList; @@ -221,16 +221,15 @@ public int getAttendCount(String authCode) { return attendanceRedisRepository.getAttendees(authCode).size(); } - public boolean isSessionActivatedByCourseId(Long courseId){ + public boolean isSessionActivatedByCourseId(Long courseId) { return courseIdRedisRepository.findById(courseId).isPresent(); } - public boolean isSessionActivatedBySessionId(Long sessionId){ + public boolean isSessionActivatedBySessionId(Long sessionId) { return sessionIdRedisRepository.findById(sessionId).isPresent(); } - private String generateAuthCode() { String generatedAuthCode = ""; while (true) { diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeService.java b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeService.java index 4fdd27c..ad344af 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeService.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeService.java @@ -23,7 +23,5 @@ public interface AttendeeService { public DuplicateAttendees getDuplicatesAll(Long courseId, List newAttendees); - public AttendeeDetailDto getAttendanceCount(Long attendeeId); - public void updateAll(Long courseId, List updatedAttendees); } diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java index 33bddd3..d6eb99c 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/AttendeeServiceImpl.java @@ -177,33 +177,6 @@ public int getAllByCourseId(Long courseId) { return attendeeRepository.findAttendeesByCourse_Id(courseId).size(); } - @Transactional(readOnly = true) - public AttendeeDetailDto getAttendanceCount(Long attendeeId) { - Attendee attendee = attendeeRepository.findById(attendeeId) - .orElseThrow(() -> new IllegalArgumentException("참여자가 존재하지 않습니다.")); - - List attendanceInfoByAttendeeId = attendeeRepository.findAttendanceInfoByAttendeeId( - attendeeId); - - int attendance = 0; - int absence = 0; - - for (AttendeeAttendDetailInfo attendDetailInfo : attendanceInfoByAttendeeId) { - if (attendDetailInfo.getAttendanceStatus()) { - attendance++; - } else { - absence++; - } - } - - return AttendeeDetailDto.builder() - .attendee(attendee) - .attendance(attendance) - .absence(absence) - .attendanceInfo(attendanceInfoByAttendeeId) - .build(); - } - @Override public void updateAll(Long courseId, List updatedAttendees) { diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index fc29989..1d371cc 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -29,7 +29,6 @@ public class SessionCommandServiceImpl implements SessionCommandService { private final CourseRepository courseRepository; private final AttendanceRepository attendanceRepository; private final AttendeeRepository attendeeRepository; - private final ActiveSessionService activeSessionService; public void create(Long courseId, String sessionName) { // TODO : exception 수정 From 18abf31e6f5fc3688db6b02a274f2d1c06439c36 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Tue, 16 Apr 2024 18:42:06 +0900 Subject: [PATCH 09/19] =?UTF-8?q?Refactor/attend:=20=EC=B6=9C=EC=84=9D=20?= =?UTF-8?q?=EC=9D=BC=EA=B4=84=20Batch=20=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20A?= =?UTF-8?q?ctiveSession=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#49)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ActiveSessionAttendanceController.java | 43 ++++ .../active/domain/entity/CourseId.java | 28 --- .../entity/CurrentSessionAttendanceInfo.java | 24 +++ .../active/domain/entity/SessionId.java | 29 --- .../repository/ActiveSessionRepository.java | 12 ++ .../repository/AttendanceRedisRepository.java | 36 ---- .../repository/AuthCodeRedisRepository.java | 9 - .../repository/CourseIdRedisRepository.java | 7 - .../repository/SessionIdRedisRepository.java | 9 - .../ActiveAttendanceService.java} | 10 +- .../ActiveAttendanceServiceImpl.java} | 79 ++----- .../active/service/ActiveSessionService.java | 9 + .../service/ActiveSessionServiceImpl.java | 50 +++++ .../controller/AuthCodeController.java | 63 ------ .../repository/AttendanceBatchRepository.java | 46 ++++ .../service/AttendanceServiceImpl.java | 24 +-- .../service/rdb/AttendanceRDBService.java | 8 +- .../service/rdb/AttendanceRDBServiceImpl.java | 87 +++----- .../command/AttendeeCommandServiceImpl.java | 8 +- .../areyouhere/common/config/RedisConfig.java | 18 +- .../course/service/CourseServiceImpl.java | 10 +- .../session/service/SessionService.java | 31 --- .../session/service/SessionServiceImpl.java | 199 ------------------ .../command/SessionCommandServiceImpl.java | 2 - .../query/SessionQueryServiceImpl.java | 20 +- 25 files changed, 276 insertions(+), 585 deletions(-) create mode 100644 src/main/java/com/waruru/areyouhere/active/ActiveSessionAttendanceController.java delete mode 100644 src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java delete mode 100644 src/main/java/com/waruru/areyouhere/active/domain/entity/SessionId.java create mode 100644 src/main/java/com/waruru/areyouhere/active/domain/repository/ActiveSessionRepository.java delete mode 100644 src/main/java/com/waruru/areyouhere/active/domain/repository/AttendanceRedisRepository.java delete mode 100644 src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java delete mode 100644 src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java delete mode 100644 src/main/java/com/waruru/areyouhere/active/domain/repository/SessionIdRedisRepository.java rename src/main/java/com/waruru/areyouhere/active/{ActiveSessionService.java => service/ActiveAttendanceService.java} (84%) rename src/main/java/com/waruru/areyouhere/active/{ActiveSessionServiceImpl.java => service/ActiveAttendanceServiceImpl.java} (69%) create mode 100644 src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java create mode 100644 src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java delete mode 100644 src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java create mode 100644 src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceBatchRepository.java delete mode 100644 src/main/java/com/waruru/areyouhere/session/service/SessionService.java delete mode 100644 src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java diff --git a/src/main/java/com/waruru/areyouhere/active/ActiveSessionAttendanceController.java b/src/main/java/com/waruru/areyouhere/active/ActiveSessionAttendanceController.java new file mode 100644 index 0000000..5e265e1 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/active/ActiveSessionAttendanceController.java @@ -0,0 +1,43 @@ +package com.waruru.areyouhere.active; + + +import com.waruru.areyouhere.attendance.dto.request.AuthCodeDeactivationRequestDto; +import com.waruru.areyouhere.attendance.dto.request.AuthCodeRequestDto; +import com.waruru.areyouhere.active.service.ActiveSessionService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping(ActiveSessionAttendanceController.AUTH_CODE_API_URL) +public class ActiveSessionAttendanceController { + + public static final String AUTH_CODE_API_URL = "/api/auth-code"; + + private final ActiveSessionService activeSessionService; + + + @PostMapping + public ResponseEntity activate(@RequestBody AuthCodeRequestDto authCodeRequestDto) { + Long sessionId = authCodeRequestDto.getSessionId(); + Long courseId = authCodeRequestDto.getCourseId(); + return ResponseEntity.ok(activeSessionService.activateSession(sessionId, courseId)); + } + + @PostMapping("/deactivate") + public ResponseEntity deactivate( + @RequestBody AuthCodeDeactivationRequestDto authCodeDeactivationRequestDto) { + Long sessionId = authCodeDeactivationRequestDto.getSessionId(); + Long courseId = authCodeDeactivationRequestDto.getCourseId(); + String authCode = authCodeDeactivationRequestDto.getAuthCode(); + activeSessionService.deactivateSession(authCode, sessionId, courseId); + return ResponseEntity.ok().build(); + } + + +} diff --git a/src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java b/src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java deleted file mode 100644 index 197e0ef..0000000 --- a/src/main/java/com/waruru/areyouhere/active/domain/entity/CourseId.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.waruru.areyouhere.active.domain.entity; - - -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.data.annotation.Id; -import org.springframework.data.redis.core.RedisHash; - -@Getter -@RedisHash(value = "course_id") -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class CourseId { - @Id - @NotNull - private long courseId; - - @NotNull - private String authCode; - - @Builder - public CourseId(long courseId, String authCode) { - this.courseId = courseId; - this.authCode = authCode; - } -} diff --git a/src/main/java/com/waruru/areyouhere/active/domain/entity/CurrentSessionAttendanceInfo.java b/src/main/java/com/waruru/areyouhere/active/domain/entity/CurrentSessionAttendanceInfo.java index 05b0166..18c87de 100644 --- a/src/main/java/com/waruru/areyouhere/active/domain/entity/CurrentSessionAttendanceInfo.java +++ b/src/main/java/com/waruru/areyouhere/active/domain/entity/CurrentSessionAttendanceInfo.java @@ -5,7 +5,9 @@ import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -16,6 +18,7 @@ import lombok.Setter; import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; +import org.springframework.data.redis.core.index.Indexed; @Getter @RedisHash(value = "auth_code") @@ -26,13 +29,18 @@ public class CurrentSessionAttendanceInfo { private String authCode; @NotNull + @Indexed private long sessionId; @NotNull + @Indexed private long courseId; private List attendees; + @Getter + private Map attendanceTime = new HashMap<>(); + @NotNull @Setter private String courseName; @@ -74,4 +82,20 @@ public void updateAttendees(List attendees){ .toList(); } + public void setAttendanceTime(Long attendeeId, LocalDateTime time){ + attendanceTime.put(attendeeId, time); + } + + public void removeAttendanceTime(Long attendeeId){ + attendanceTime.remove(attendeeId); + } + + public Set getAttendAttendeesIds(){ + return attendanceTime.keySet(); + } + + public boolean isAlreadyAttended(Long attendeeId){ + return attendanceTime.containsKey(attendeeId); + } + } diff --git a/src/main/java/com/waruru/areyouhere/active/domain/entity/SessionId.java b/src/main/java/com/waruru/areyouhere/active/domain/entity/SessionId.java deleted file mode 100644 index 8b88405..0000000 --- a/src/main/java/com/waruru/areyouhere/active/domain/entity/SessionId.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.waruru.areyouhere.active.domain.entity; - - - -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.data.annotation.Id; -import org.springframework.data.redis.core.RedisHash; - -@Getter -@RedisHash(value = "session_id") -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class SessionId { - @Id - @NotNull - private long sessionId; - - @NotNull - private String authCode; - - @Builder - public SessionId(long sessionId, String authCode) { - this.sessionId = sessionId; - this.authCode = authCode; - } -} diff --git a/src/main/java/com/waruru/areyouhere/active/domain/repository/ActiveSessionRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/ActiveSessionRepository.java new file mode 100644 index 0000000..889b929 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/active/domain/repository/ActiveSessionRepository.java @@ -0,0 +1,12 @@ +package com.waruru.areyouhere.active.domain.repository; + +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; +import java.util.Optional; +import org.springframework.data.repository.CrudRepository; + + +public interface ActiveSessionRepository extends CrudRepository{ + Optional findBySessionId(long sessionId); + + Optional findByCourseId(long courseId); +} diff --git a/src/main/java/com/waruru/areyouhere/active/domain/repository/AttendanceRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/AttendanceRedisRepository.java deleted file mode 100644 index d2c364b..0000000 --- a/src/main/java/com/waruru/areyouhere/active/domain/repository/AttendanceRedisRepository.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.waruru.areyouhere.active.domain.repository; - -import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class AttendanceRedisRepository { - private final RedisTemplate redisTemplate; - - private final String ATTENDANCE_KEY = "attendance"; - - public boolean isAlreadyAttended(String authCode, AttendeeRedisData attendeeInfo){ - Set attendedMembers = redisTemplate.opsForSet().members(ATTENDANCE_KEY + authCode); - return attendedMembers == null || attendedMembers.contains(attendeeInfo.getId()); - } - - public Set getAttendees(String authCode){ - return redisTemplate.opsForSet().members(ATTENDANCE_KEY + authCode); - } - - public void setAttend(String authCode, AttendeeRedisData attendeeInfo){ - redisTemplate.opsForSet().add(ATTENDANCE_KEY + authCode, attendeeInfo.getId()); - } - - public void deleteAllAttendanceInSession(String authCode){ - redisTemplate.delete(ATTENDANCE_KEY + authCode); - } - - -} - - diff --git a/src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java deleted file mode 100644 index 47ff117..0000000 --- a/src/main/java/com/waruru/areyouhere/active/domain/repository/AuthCodeRedisRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.waruru.areyouhere.active.domain.repository; - -import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; -import org.springframework.data.repository.CrudRepository; - - -public interface AuthCodeRedisRepository extends CrudRepository{ - -} diff --git a/src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java deleted file mode 100644 index 473d908..0000000 --- a/src/main/java/com/waruru/areyouhere/active/domain/repository/CourseIdRedisRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.waruru.areyouhere.active.domain.repository; - -import com.waruru.areyouhere.active.domain.entity.CourseId; -import org.springframework.data.repository.CrudRepository; - -public interface CourseIdRedisRepository extends CrudRepository { -} diff --git a/src/main/java/com/waruru/areyouhere/active/domain/repository/SessionIdRedisRepository.java b/src/main/java/com/waruru/areyouhere/active/domain/repository/SessionIdRedisRepository.java deleted file mode 100644 index ea201e4..0000000 --- a/src/main/java/com/waruru/areyouhere/active/domain/repository/SessionIdRedisRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.waruru.areyouhere.active.domain.repository; - -import com.waruru.areyouhere.active.domain.entity.SessionId; -import org.springframework.data.repository.CrudRepository; - -public interface SessionIdRedisRepository extends CrudRepository { - - -} diff --git a/src/main/java/com/waruru/areyouhere/active/ActiveSessionService.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceService.java similarity index 84% rename from src/main/java/com/waruru/areyouhere/active/ActiveSessionService.java rename to src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceService.java index fb365bf..69a657a 100644 --- a/src/main/java/com/waruru/areyouhere/active/ActiveSessionService.java +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceService.java @@ -1,4 +1,4 @@ -package com.waruru.areyouhere.active; +package com.waruru.areyouhere.active.service; import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; @@ -11,13 +11,13 @@ import java.time.LocalDateTime; import java.util.List; -public interface ActiveSessionService { +public interface ActiveAttendanceService { public List getNameSakeInfos(String authCode, String attendeeName); public AuthCodeInfo isAttendPossible(String authCode, String attendanceName, Long attendeeId); - public String createAuthCode(Course course, Session sessionId, LocalDateTime currentTime); + public String activate(Course course, Session sessionId, LocalDateTime currentTime); public void deactivate(String authCode); @@ -38,14 +38,10 @@ public AttendeeRedisData findByNameIfNotDuplicatedOrId(String attendeeName, Long public void updateCourseName(Long courseId, String courseName); - public void updateSessionName(Long courseId, String sessionName); public void updateAttendees(Long courseId, List attendees); - public boolean isSessionActivatedByCourseId(Long courseId); - public boolean isSessionActivatedBySessionId(Long sessionId); - } diff --git a/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceServiceImpl.java similarity index 69% rename from src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java rename to src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceServiceImpl.java index 2f317b2..6d71a62 100644 --- a/src/main/java/com/waruru/areyouhere/active/ActiveSessionServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceServiceImpl.java @@ -1,9 +1,6 @@ -package com.waruru.areyouhere.active; +package com.waruru.areyouhere.active.service; -import com.waruru.areyouhere.active.domain.entity.CourseId; -import com.waruru.areyouhere.active.domain.repository.CourseIdRedisRepository; import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; -import com.waruru.areyouhere.active.domain.repository.AttendanceRedisRepository; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; @@ -12,9 +9,7 @@ import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.active.domain.entity.SessionId; -import com.waruru.areyouhere.active.domain.repository.AuthCodeRedisRepository; -import com.waruru.areyouhere.active.domain.repository.SessionIdRedisRepository; +import com.waruru.areyouhere.active.domain.repository.ActiveSessionRepository; import com.waruru.areyouhere.attendance.exception.AuthCodeNotFoundException; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; import com.waruru.areyouhere.attendance.exception.AlreadyAttendException; @@ -31,14 +26,11 @@ @Service @RequiredArgsConstructor -public class ActiveSessionServiceImpl implements ActiveSessionService { +public class ActiveAttendanceServiceImpl implements ActiveAttendanceService { - private final AuthCodeRedisRepository authCodeRedisRepository; - private final SessionIdRedisRepository sessionIdRedisRepository; - private final AttendanceRedisRepository attendanceRedisRepository; + private final ActiveSessionRepository activeSessionRepository; private final AttendeeRepository attendeeRepository; private final RandomIdentifierGenerator randomIdentifierGenerator; - private final CourseIdRedisRepository courseIdRedisRepository; @Override @@ -66,7 +58,7 @@ public AuthCodeInfo isAttendPossible(String authCode, String attendeeName, Long AttendeeRedisData attendeeInfo = findByNameIfNotDuplicatedOrId(attendeeName, attendeeId, currentSessionAttendanceInfoData); - if (attendanceRedisRepository.isAlreadyAttended(authCode, attendeeInfo)) { + if (currentSessionAttendanceInfoData.isAlreadyAttended(attendeeId)) { throw new AlreadyAttendException(); } @@ -80,12 +72,15 @@ public AuthCodeInfo isAttendPossible(String authCode, String attendeeName, Long @Override public void setAttendInRedis(String authCode, AttendeeRedisData attendeeInfo) { - attendanceRedisRepository.setAttend(authCode, attendeeInfo); + CurrentSessionAttendanceInfo currentSessionAttendanceInfoData = getSessionAttendanceInfoOrThrow( + authCode); + currentSessionAttendanceInfoData.setAttendanceTime(attendeeInfo.getId(), LocalDateTime.now()); + activeSessionRepository.save(currentSessionAttendanceInfoData); } @Override - public String createAuthCode(Course course, Session session, LocalDateTime currentTime) { + public String activate(Course course, Session session, LocalDateTime currentTime) { String generatedAuthCode = generateAuthCode(); List attendeesByCourseId = attendeeRepository.findAttendeesByCourse_Id(course.getId()); @@ -99,21 +94,7 @@ public String createAuthCode(Course course, Session session, LocalDateTime curre .courseName(course.getName()) .build(); - authCodeRedisRepository.save(currentSessionAttendanceInfo); - - SessionId newsessionId = SessionId.builder() - .authCode(currentSessionAttendanceInfo.getAuthCode()) - .sessionId(session.getId()) - .build(); - - sessionIdRedisRepository.save(newsessionId); - - CourseId courseId = CourseId.builder() - .authCode(currentSessionAttendanceInfo.getAuthCode()) - .courseId(course.getId()) - .build(); - - courseIdRedisRepository.save(courseId); + activeSessionRepository.save(currentSessionAttendanceInfo); return generatedAuthCode; } @@ -125,10 +106,7 @@ public void deactivate(String authCode) { CurrentSessionAttendanceInfo authCodeByCurrentSessionAttendanceInfo = getSessionAttendanceInfoOrThrow( authCode); - authCodeRedisRepository.delete(authCodeByCurrentSessionAttendanceInfo); - courseIdRedisRepository.deleteById(authCodeByCurrentSessionAttendanceInfo.getCourseId()); - sessionIdRedisRepository.deleteById(authCodeByCurrentSessionAttendanceInfo.getSessionId()); - attendanceRedisRepository.deleteAllAttendanceInSession(authCodeByCurrentSessionAttendanceInfo.getAuthCode()); + activeSessionRepository.delete(authCodeByCurrentSessionAttendanceInfo); } public CurrentSessionAttendeeAttendance getCurrentSessionAttendees(String authCode) { @@ -136,7 +114,7 @@ public CurrentSessionAttendeeAttendance getCurrentSessionAttendees(String authCo authCode); List attendees = new LinkedList<>(); List absentees = new LinkedList<>(); - Set attendeesChecker = attendanceRedisRepository.getAttendees(authCode); + Set attendeesChecker = currentSessionAttendanceInfoData.getAttendAttendeesIds(); currentSessionAttendanceInfoData.getAttendees() .forEach(att -> { if (attendeesChecker.contains(att.getId())) { @@ -170,13 +148,13 @@ public AttendeeRedisData findByNameIfNotDuplicatedOrId(String attendeeName, Long } public String findAuthCodeBySessionId(Long sessionId) { - return sessionIdRedisRepository.findById(sessionId) + return activeSessionRepository.findBySessionId(sessionId) .orElseThrow(AuthCodeNotFoundException::new).getAuthCode(); } public int getTotalAttendees(String authCode) { - return authCodeRedisRepository.findById(authCode) + return activeSessionRepository.findById(authCode) .orElseThrow(AuthCodeNotFoundException::new).getAttendees().size(); } @@ -184,15 +162,7 @@ public void updateCourseName(Long courseId, String courseName) { getCurrentSessionAttendanceInfoByCourseId(courseId) .ifPresent(currentSessionAttendanceInfoData -> { currentSessionAttendanceInfoData.setCourseName(courseName); - authCodeRedisRepository.save(currentSessionAttendanceInfoData); - }); - } - - public void updateSessionName(Long courseId, String sessionName) { - getCurrentSessionAttendanceInfoByCourseId(courseId) - .ifPresent(currentSessionAttendanceInfoData -> { - currentSessionAttendanceInfoData.setSessionName(sessionName); - authCodeRedisRepository.save(currentSessionAttendanceInfoData); + activeSessionRepository.save(currentSessionAttendanceInfoData); }); } @@ -200,33 +170,28 @@ public void updateAttendees(Long courseId, List attendees) { getCurrentSessionAttendanceInfoByCourseId(courseId) .ifPresent(currentSessionAttendanceInfoData -> { currentSessionAttendanceInfoData.updateAttendees(attendees); - authCodeRedisRepository.save(currentSessionAttendanceInfoData); + activeSessionRepository.save(currentSessionAttendanceInfoData); }); } public Optional getCurrentSessionAttendanceInfoByCourseId(Long courseId) { - return courseIdRedisRepository.findById(courseId) - .flatMap(findCourseId -> authCodeRedisRepository.findById(findCourseId.getAuthCode())); + return activeSessionRepository.findByCourseId(courseId); } public CurrentSessionAttendanceInfo getSessionAttendanceInfoOrThrow(String authCode) { - return authCodeRedisRepository + return activeSessionRepository .findById(authCode) .orElseThrow(AuthCodeNotFoundException::new); } public int getAttendCount(String authCode) { - return attendanceRedisRepository.getAttendees(authCode).size(); + return getSessionAttendanceInfoOrThrow(authCode).getAttendAttendeesIds().size(); } public boolean isSessionActivatedByCourseId(Long courseId) { - return courseIdRedisRepository.findById(courseId).isPresent(); - } - - public boolean isSessionActivatedBySessionId(Long sessionId) { - return sessionIdRedisRepository.findById(sessionId).isPresent(); + return activeSessionRepository.findByCourseId(courseId).isPresent(); } @@ -234,7 +199,7 @@ private String generateAuthCode() { String generatedAuthCode = ""; while (true) { generatedAuthCode = randomIdentifierGenerator.generateRandomIdentifier(4); - Optional authCodeData = authCodeRedisRepository + Optional authCodeData = activeSessionRepository .findById(generatedAuthCode); if (authCodeData.isEmpty()) { diff --git a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java new file mode 100644 index 0000000..e7d61c5 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java @@ -0,0 +1,9 @@ +package com.waruru.areyouhere.active.service; + +public interface ActiveSessionService { + + public void deactivateSession(String authCode, Long sessionId, Long courseId); + + public String activateSession(Long sessionId, Long courseId); + +} diff --git a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java new file mode 100644 index 0000000..64a7abe --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java @@ -0,0 +1,50 @@ +package com.waruru.areyouhere.active.service; + +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; +import com.waruru.areyouhere.attendance.service.rdb.AttendanceRDBService; +import com.waruru.areyouhere.course.domain.entity.Course; +import com.waruru.areyouhere.course.service.CourseService; +import com.waruru.areyouhere.session.domain.entity.Session; +import com.waruru.areyouhere.session.service.command.SessionCommandService; +import com.waruru.areyouhere.session.service.query.SessionQueryService; +import java.time.LocalDateTime; +import java.time.ZoneId; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class ActiveSessionServiceImpl implements ActiveSessionService { + + private final CourseService courseService; + private final SessionQueryService sessionQueryService; + private final SessionCommandService sessionCommandService; + private final AttendanceRDBService attendanceRDBService; + private final ActiveAttendanceService activeAttendanceService; + + @Override + @Transactional + public String activateSession(Long sessionId, Long courseId) { + Course course = courseService.get(courseId); + Session session = sessionQueryService.get(sessionId); + LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); + return activeAttendanceService.activate(course, session, currentTime); + } + + @Override + @Transactional + public void deactivateSession(String authCode, Long sessionId, Long courseId) { + sessionQueryService.checkNotDeactivated(sessionId); + + CurrentSessionAttendanceInfo currentSessionAttendanceInfo = activeAttendanceService.getSessionAttendanceInfoOrThrow( + authCode); + attendanceRDBService.setAttendancesAfterDeactivate(courseId, sessionId, currentSessionAttendanceInfo); + sessionCommandService.deactivate(sessionId); + activeAttendanceService.deactivate(authCode); + } + + +} diff --git a/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java b/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java deleted file mode 100644 index 5d7ab81..0000000 --- a/src/main/java/com/waruru/areyouhere/attendance/controller/AuthCodeController.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.waruru.areyouhere.attendance.controller; - - -import com.waruru.areyouhere.attendance.service.rdb.AttendanceRDBService; -import com.waruru.areyouhere.course.domain.entity.Course; -import com.waruru.areyouhere.course.service.CourseService; -import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.attendance.dto.request.AuthCodeDeactivationRequestDto; -import com.waruru.areyouhere.attendance.dto.request.AuthCodeRequestDto; -import com.waruru.areyouhere.active.ActiveSessionService; -import com.waruru.areyouhere.session.service.command.SessionCommandService; -import com.waruru.areyouhere.session.service.query.SessionQueryService; -import java.time.LocalDateTime; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping(AuthCodeController.AUTH_CODE_API_URL) -public class AuthCodeController { - - public static final String AUTH_CODE_API_URL = "/api/auth-code"; - - private final ActiveSessionService activeSessionService; - private final AttendanceRDBService attendanceRDBService; - private final SessionCommandService sessionCommandService; - private final SessionQueryService sessionQueryService; - private final CourseService courseService; - - - @PostMapping - public ResponseEntity create(@RequestBody AuthCodeRequestDto authCodeRequestDto) { - LocalDateTime currentTime = LocalDateTime.now(); - Long sessionId = authCodeRequestDto.getSessionId(); - Long courseId = authCodeRequestDto.getCourseId(); - Course course = courseService.get(courseId); - Session session = sessionQueryService.get(sessionId); - sessionCommandService.setStartTime(sessionId, currentTime); - return ResponseEntity.ok(activeSessionService.createAuthCode(course, session, currentTime)); - } - - @PostMapping("/deactivate") - public ResponseEntity deactivate( - @RequestBody AuthCodeDeactivationRequestDto authCodeDeactivationRequestDto) { - Long sessionId = authCodeDeactivationRequestDto.getSessionId(); - Long courseId = authCodeDeactivationRequestDto.getCourseId(); - - String authCode = authCodeDeactivationRequestDto.getAuthCode(); - - sessionQueryService.checkNotDeactivated(sessionId); - sessionCommandService.deactivate(sessionId); - activeSessionService.deactivate(authCode); - attendanceRDBService.setAbsentAfterDeactivation(courseId, sessionId); - return ResponseEntity.ok().build(); - } - - -} diff --git a/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceBatchRepository.java b/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceBatchRepository.java new file mode 100644 index 0000000..9a49dc0 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/attendance/domain/repository/AttendanceBatchRepository.java @@ -0,0 +1,46 @@ +package com.waruru.areyouhere.attendance.domain.repository; + +import com.waruru.areyouhere.attendance.domain.entity.Attendance; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class AttendanceBatchRepository { + private final JdbcTemplate jdbcTemplate; + + + + @Modifying(clearAutomatically = true) + public void insertAbsentBatch(List attendances, Boolean isAttended, Long sessionId, LocalDateTime currentTime) { + jdbcTemplate.batchUpdate("INSERT INTO attendance (is_attended, attendee_id, session_id, created_at) VALUES (?, ?, ?, ?)", + attendances, + attendances.size(), + (ps, attendance) -> { + ps.setBoolean(1, isAttended); + ps.setLong(2, attendance.getId()); + ps.setLong(3, sessionId); + ps.setObject(4, Timestamp.valueOf(currentTime)); + }); + } + + @Modifying(clearAutomatically = true) + public void insertAttendBatch(List attendances, Boolean isAttended, Long sessionId, Map attendanceTime) { + jdbcTemplate.batchUpdate("INSERT INTO attendance (is_attended, attendee_id, session_id, created_at) VALUES (?, ?, ?, ?)", + attendances, + attendances.size(), + (ps, attendance) -> { + ps.setBoolean(1, isAttended); + ps.setLong(2, attendance.getId()); + ps.setLong(3, sessionId); + ps.setObject(4, Timestamp.valueOf(attendanceTime.get(attendance.getId()))); + }); + } +} diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java index 12888da..add6e0d 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/AttendanceServiceImpl.java @@ -6,7 +6,7 @@ import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendCount; import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import com.waruru.areyouhere.attendance.service.rdb.AttendanceRDBService; -import com.waruru.areyouhere.active.ActiveSessionService; +import com.waruru.areyouhere.active.service.ActiveAttendanceService; import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; import com.waruru.areyouhere.session.service.dto.AuthCodeInfo; import java.time.LocalDateTime; @@ -22,13 +22,13 @@ @RequiredArgsConstructor public class AttendanceServiceImpl implements AttendanceService { private final AttendanceRDBService attendanceRDBService; - private final ActiveSessionService activeSessionService; + private final ActiveAttendanceService activeAttendanceService; @Override @Transactional public AttendResponseDto attend(String attendeeName, String authCode, Long attendeeId) { LocalDateTime attendanceTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); - List nameSakeAttendees = activeSessionService.getNameSakeInfos(authCode, attendeeName); + List nameSakeAttendees = activeAttendanceService.getNameSakeInfos(authCode, attendeeName); // 동명이인 응답 if (attendeeId == null && nameSakeAttendees.size() > 1) { @@ -37,12 +37,11 @@ public AttendResponseDto attend(String attendeeName, String authCode, Long atten .build(); } - AuthCodeInfo authCodeInfo = activeSessionService.isAttendPossible(authCode, attendeeName, attendeeId); - attendanceRDBService.setAttend(authCodeInfo.getSessionId(), attendeeName, attendeeId); - AttendeeRedisData attendeeInSession = activeSessionService.findByNameIfNotDuplicatedOrId(attendeeName, + AuthCodeInfo authCodeInfo = activeAttendanceService.isAttendPossible(authCode, attendeeName, attendeeId); + AttendeeRedisData attendeeInSession = activeAttendanceService.findByNameIfNotDuplicatedOrId(attendeeName, attendeeId, - activeSessionService.getSessionAttendanceInfoOrThrow(authCode)); - activeSessionService.setAttendInRedis(authCode, attendeeInSession); + activeAttendanceService.getSessionAttendanceInfoOrThrow(authCode)); + activeAttendanceService.setAttendInRedis(authCode, attendeeInSession); return AttendResponseDto.builder() .attendanceName(attendeeName) @@ -61,17 +60,18 @@ public void updateAllStatuses(Long sessionId, List updateAtten @Override @Transactional(readOnly = true) public CurrentSessionAttendCount getCurrentSessionAttendCount(Long sessionId) { - String authCode = activeSessionService.findAuthCodeBySessionId(sessionId); - int total = activeSessionService.getTotalAttendees(authCode); - int attendeeCount = activeSessionService.getAttendCount(authCode); + String authCode = activeAttendanceService.findAuthCodeBySessionId(sessionId); + int total = activeAttendanceService.getTotalAttendees(authCode); + int attendeeCount = activeAttendanceService.getAttendCount(authCode); return new CurrentSessionAttendCount(total, attendeeCount); } @Override @Transactional(readOnly = true) public CurrentSessionAttendeeAttendance getCurrentSessionAttendeesAndAbsentees(String authCode) { - return activeSessionService.getCurrentSessionAttendees(authCode); + return activeAttendanceService.getCurrentSessionAttendees(authCode); } + } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBService.java b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBService.java index 40300f3..a6bf7cb 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBService.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBService.java @@ -1,14 +1,12 @@ package com.waruru.areyouhere.attendance.service.rdb; +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.attendance.dto.UpdateAttendance; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import java.util.List; public interface AttendanceRDBService { - public void setAbsentAfterDeactivation(long courseId, long sessionId); - - public void setAttend(Long sessionId, String attendanceName, Long attendeeId); + public void setAttendancesAfterDeactivate(long courseId, long sessionId, CurrentSessionAttendanceInfo currentSessionAttendanceInfo); public void setAttendanceStatuses(Long sessionId, List updateAttendances); - - public int currentAttendance(Long sessionId); } diff --git a/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBServiceImpl.java index 4dc701f..b90b7c0 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendance/service/rdb/AttendanceRDBServiceImpl.java @@ -1,15 +1,23 @@ package com.waruru.areyouhere.attendance.service.rdb; +import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.attendance.domain.entity.Attendance; +import com.waruru.areyouhere.attendance.domain.repository.AttendanceBatchRepository; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; +import com.waruru.areyouhere.attendance.dto.AttendeeRedisData; import com.waruru.areyouhere.attendance.dto.UpdateAttendance; +import com.waruru.areyouhere.attendance.service.dto.CurrentSessionAttendeeAttendance; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; import com.waruru.areyouhere.session.domain.entity.Session; import com.waruru.areyouhere.session.domain.repository.SessionRepository; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; +import java.time.LocalDateTime; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -24,42 +32,29 @@ public class AttendanceRDBServiceImpl implements AttendanceRDBService { private final AttendanceRepository attendanceRepository; - private final AttendeeRepository attendeeRepository; - private final SessionRepository sessionRepository; + private final AttendanceBatchRepository attendanceBatchRepository; - @Override - public void setAbsentAfterDeactivation(long courseId, long sessionId) { - - List absenteeBySessionId = attendeeRepository.findAbsenteeBySessionIdWhenNoRegister(courseId, - sessionId); - Session session = sessionRepository.findById(sessionId).orElseThrow(SessionIdNotFoundException::new); - List attendances = absenteeBySessionId.stream().map(attendee -> Attendance.builder() - .attendee((attendee)) - .session(session) - .isAttended(false) - .build()).toList(); - attendanceRepository.saveAll(attendances); - } - - @Async - public void setAttend(Long sessionId, String attendanceName, Long attendeeId) { - Session session = sessionRepository.findById(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - Long courseId = session.getCourse().getId(); // lazy loading? - List attendeesByCourseId = attendeeRepository.findAttendeesByCourse_Id(courseId); - - Attendee attendee = getAttendee(attendanceName, attendeeId, - attendeesByCourseId); - - // TODO : attendeesByCourseId null 및 empty 체크 - - Attendance attendance = Attendance.builder() - .session(session) - .isAttended(true) - .attendee(attendee) - .build(); - attendanceRepository.save(attendance); + @Override + public void setAttendancesAfterDeactivate(long courseId, long sessionId, + CurrentSessionAttendanceInfo currentSessionAttendanceInfo) { + + LocalDateTime absentTime = LocalDateTime.now(); + List attendees = new LinkedList<>(); + List absentees = new LinkedList<>(); + Map attendanceTime = currentSessionAttendanceInfo.getAttendanceTime(); + currentSessionAttendanceInfo.getAttendees() + .forEach(att -> { + if (attendanceTime.containsKey(att.getId())) { + attendees.add(att); + } else { + absentees.add(att); + } + }); + + + attendanceBatchRepository.insertAttendBatch(attendees, true, sessionId, attendanceTime); + attendanceBatchRepository.insertAbsentBatch(absentees, false, sessionId, absentTime); } @@ -77,29 +72,5 @@ public void setAttendanceStatuses(Long sessionId, List updateA attendanceRepository.saveAll(attendancesToUpdate); } - @Transactional(readOnly = true) - public int currentAttendance(Long sessionId) { - List attendancesBySessionId = attendanceRepository.findAttendancesBySession_Id(sessionId); - if (attendancesBySessionId == null || attendancesBySessionId.isEmpty()) { - return 0; - } else { - return attendancesBySessionId.size(); - } - } - - - // AttendeeId가 null이 아니라는 것은 duplicatedAttendee가 발생하여 Id 기준으로 찾아야 한다는 것. - private Attendee getAttendee(String attendanceName, Long attendeeId, List attendeesByCourseId) { - return attendeeId == null ? - attendeesByCourseId.stream() - .filter(s -> s.getName().equals(attendanceName)) - .findFirst() - .orElse(null) : - attendeesByCourseId.stream() - .filter(s -> s.getId().equals(attendeeId)) - .findFirst() - .orElse(null); - } - } diff --git a/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java index 2645644..80dbe6f 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/attendee/service/command/AttendeeCommandServiceImpl.java @@ -1,6 +1,6 @@ package com.waruru.areyouhere.attendee.service.command; -import com.waruru.areyouhere.active.ActiveSessionService; +import com.waruru.areyouhere.active.service.ActiveAttendanceService; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeBatchRepository; @@ -34,7 +34,7 @@ public class AttendeeCommandServiceImpl implements AttendeeCommandService{ private final AttendanceRepository attendanceRepository; private final AttendeeBatchRepository attendeeBatchRepository; private final CourseRepository courseRepository; - private final ActiveSessionService activeSessionService; + private final ActiveAttendanceService activeAttendanceService; @Override public void createAll(Long courseId, List newAttendees){ @@ -89,7 +89,7 @@ public void deleteAll(List deleteAttendees){ Long courseId = attendeeRepository.findById(deleteAttendees.get(0)) .orElseThrow(() -> new AttendeeNotFoundException("Attendee not found")) .getCourse().getId(); - if(activeSessionService.isSessionActivatedByCourseId(courseId)){ + if(activeAttendanceService.isSessionActivatedByCourseId(courseId)){ throw new ActivatedSessionExistsException(); } attendanceRepository.deleteAllByAttendeeIds(deleteAttendees); @@ -98,7 +98,7 @@ public void deleteAll(List deleteAttendees){ private void syncToRedis(Long courseId){ List attendees = attendeeRepository.findAttendeesByCourse_Id(courseId); - activeSessionService.updateAttendees(courseId, attendees); + activeAttendanceService.updateAttendees(courseId, attendees); } diff --git a/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java b/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java index fa6559a..e846bf7 100644 --- a/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java +++ b/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java @@ -32,15 +32,15 @@ public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(redisStandaloneConfiguration); } - @Bean - public RedisTemplate redisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); - redisTemplate.setConnectionFactory(redisConnectionFactory()); - redisTemplate.setKeySerializer( new StringRedisSerializer() ); - redisTemplate.setHashValueSerializer( new GenericToStringSerializer< Long >( Long.class ) ); - redisTemplate.setValueSerializer( new GenericToStringSerializer< Long >( Long.class ) ); - return redisTemplate; - } +// @Bean +// public RedisTemplate redisTemplate() { +// RedisTemplate redisTemplate = new RedisTemplate<>(); +// redisTemplate.setConnectionFactory(redisConnectionFactory()); +// redisTemplate.setKeySerializer( new StringRedisSerializer() ); +// redisTemplate.setHashValueSerializer( new GenericToStringSerializer< Long >( Long.class ) ); +// redisTemplate.setValueSerializer( new GenericToStringSerializer< Long >( Long.class ) ); +// return redisTemplate; +// } } diff --git a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java index 2fac304..fd92903 100644 --- a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java @@ -1,6 +1,6 @@ package com.waruru.areyouhere.course.service; -import com.waruru.areyouhere.active.ActiveSessionService; +import com.waruru.areyouhere.active.service.ActiveAttendanceService; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeBatchRepository; @@ -11,7 +11,6 @@ import com.waruru.areyouhere.course.domain.repository.CourseRepository; import com.waruru.areyouhere.attendee.exception.AttendeesNotUniqueException; import com.waruru.areyouhere.course.dto.CourseData; -import com.waruru.areyouhere.course.exception.CourseActivatedSessionException; import com.waruru.areyouhere.manager.domain.entity.Manager; import com.waruru.areyouhere.manager.domain.repository.ManagerRepository; import com.waruru.areyouhere.session.domain.entity.Session; @@ -39,7 +38,7 @@ public class CourseServiceImpl implements CourseService { private final AttendeeRepository attendeeRepository; private final AttendanceRepository attendanceRepository; private final SessionRepository sessionRepository; - private final ActiveSessionService activeSessionService; + private final ActiveAttendanceService activeAttendanceService; @Override @@ -106,12 +105,12 @@ public void update(Long managerId, Long courseId, String name, String descriptio course.update(name, description, onlyListNameAllowed); courseRepository.save(course); - activeSessionService.updateCourseName(courseId, name); + activeAttendanceService.updateCourseName(courseId, name); } @Override public void delete(Long managerId, Long courseId) { - if(activeSessionService.isSessionActivatedByCourseId(courseId)){ + if(activeAttendanceService.isSessionActivatedByCourseId(courseId)){ throw new ActivatedSessionExistsException("Session is activated"); } @@ -129,6 +128,7 @@ public void delete(Long managerId, Long courseId) { } @Override + @Transactional(readOnly = true) public Course get(Long courseId) { return courseRepository.findById(courseId). orElseThrow(() -> new IllegalArgumentException("Course not found")); diff --git a/src/main/java/com/waruru/areyouhere/session/service/SessionService.java b/src/main/java/com/waruru/areyouhere/session/service/SessionService.java deleted file mode 100644 index 8169283..0000000 --- a/src/main/java/com/waruru/areyouhere/session/service/SessionService.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.waruru.areyouhere.session.service; - -import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.session.service.dto.CurrentSessionDto; -import com.waruru.areyouhere.session.service.dto.SessionAttendanceInfo; -import java.time.LocalDateTime; -import java.util.List; - -public interface SessionService { - - public void create(Long courseId, String sessionName); - - public CurrentSessionDto getCurrentSessionInfo(Long courseId); - - public List getRecentFive(Long courseId); - - public List getAll(Long courseId); - - public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId); - - public Session get(Long sessionId); - - public void delete(List sessionId); - - public void checkNotDeactivated(Long sessionId); - - public void deactivate(Long sessionId); - - public void setStartTime(Long sessionId, LocalDateTime currentTime); - -} diff --git a/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java deleted file mode 100644 index ea5d27d..0000000 --- a/src/main/java/com/waruru/areyouhere/session/service/SessionServiceImpl.java +++ /dev/null @@ -1,199 +0,0 @@ -package com.waruru.areyouhere.session.service; - -import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; -import com.waruru.areyouhere.course.domain.entity.Course; -import com.waruru.areyouhere.course.domain.repository.CourseRepository; -import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; -import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.active.domain.entity.SessionId; -import com.waruru.areyouhere.active.domain.repository.AuthCodeRedisRepository; -import com.waruru.areyouhere.active.domain.repository.SessionIdRedisRepository; -import com.waruru.areyouhere.session.domain.repository.SessionRepository; -import com.waruru.areyouhere.session.domain.repository.dto.SessionInfo; -import com.waruru.areyouhere.session.exception.CurrentSessionDeactivatedException; -import com.waruru.areyouhere.session.exception.CurrentSessionNotFoundException; -import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; -import com.waruru.areyouhere.session.service.dto.CurrentSessionDto; -import com.waruru.areyouhere.session.service.dto.SessionAttendanceInfo; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -//TODO : user 정보에 따른 course가 맞는지 확인하는 로직 추가. 보안. -@Service -@RequiredArgsConstructor -@Transactional -public class SessionServiceImpl implements SessionService { - - private final SessionRepository sessionRepository; - private final CourseRepository courseRepository; - private final AuthCodeRedisRepository authCodeRedisRepository; - private final SessionIdRedisRepository sessionIdRedisRepository; - private final AttendanceRepository attendanceRepository; - - public void create(Long courseId, String sessionName) { - // TODO : exception 수정 - Course course = courseRepository.findById(courseId) - .orElseThrow(SessionIdNotFoundException::new); - - Session session = Session.builder() - .name(sessionName) - .course(course) - .isDeactivated(false) - .build(); - sessionRepository.save(session); - } - - @Override - public void delete(List sessionIds) { - sessionIds.forEach(sessionId -> { - attendanceRepository.deleteAllBySessionId(sessionId); - sessionRepository.findById(sessionId).orElseThrow(CurrentSessionNotFoundException::new); - }); - sessionRepository.deleteAllByIds(sessionIds); - } - - // TODO : 리팩토링 노타임.. - @Transactional(readOnly = true) - @Override - public CurrentSessionDto getCurrentSessionInfo(Long courseId) { - Session mostRecentSession = sessionRepository - .findMostRecentSessionByCourseId(courseId) - .orElseThrow(CurrentSessionNotFoundException::new); - // 제일 최근 세션이 이미 출석 체크가 끝났는지 - if (mostRecentSession.isDeactivated()) { - throw new CurrentSessionDeactivatedException(); - } - // 제일 최근 세션이 출석 코드를 만들지 않았는지 - SessionId sessionId = sessionIdRedisRepository - .findById(mostRecentSession.getId()) - .orElse(null); - - if (sessionId == null) { - return CurrentSessionDto.builder() - .authCode(null) - .sessionTime(null) - .sessionName(mostRecentSession.getName()) - .id(mostRecentSession.getId()) - .build(); - } - // 제일 최근 세션이 출석 코드를 만들었다면. - // warning! 널 익셉션이 발생한다면 authCode를 redis에 삽입하는 과정에서 어느 쪽이 빠져있는 것이다. - - CurrentSessionAttendanceInfo currentSessionAttendanceInfo = authCodeRedisRepository - .findById(sessionId.getAuthCode()) - .orElse(null); - - return CurrentSessionDto.builder() - .authCode(currentSessionAttendanceInfo.getAuthCode()) - .sessionTime(currentSessionAttendanceInfo.getCreatedAt()) - .sessionName(mostRecentSession.getName()) - .id(mostRecentSession.getId()) - .build(); - } - - @Transactional(readOnly = true) - @Override - public List getRecentFive(Long courseId) { - List recentFiveSessions = sessionRepository.findTOP6BySessionByCourseId(courseId); - if (recentFiveSessions == null || recentFiveSessions.isEmpty()) { - return Collections.emptyList(); - } - - if (!recentFiveSessions.get(0).isDeactivated()) { - recentFiveSessions.remove(0); - - } else { - if (recentFiveSessions.size() > 5) { - recentFiveSessions.remove(5); - } - } - List list = new ArrayList<>(); - for (Session recentFiveSession : recentFiveSessions) { - SessionInfo sessionWithAttendance = sessionRepository.findSessionWithAttendance( - recentFiveSession.getId()) - .orElseThrow(SessionIdNotFoundException::new); - - list.add(SessionAttendanceInfo.builder() - .attendee(sessionWithAttendance.getattendee()) - .absentee(sessionWithAttendance.getabsentee()) - .date(sessionWithAttendance.getdate()) - .name(sessionWithAttendance.getname()) - .id(sessionWithAttendance.getid()) - .build() - ); - } - return list; - } - - @Transactional(readOnly = true) - @Override - public List getAll(Long courseId) { - List allSessions = sessionRepository.findSessionsWithAttendance(courseId); - return allSessions == null || allSessions.isEmpty() - ? Collections.emptyList() - : allSessions.stream().map(allSession -> SessionAttendanceInfo.builder() - .id(allSession.getid()) - .name(allSession.getname()) - .date(allSession.getdate()) - .attendee(allSession.getattendee()) - .absentee(allSession.getabsentee()) - .build() - ).toList(); - } - - @Transactional(readOnly = true) - @Override - public SessionAttendanceInfo getSessionAttendanceInfo(Long sessionId) { - SessionInfo sessionWithAttendance = sessionRepository - .findSessionWithAttendance(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - - return SessionAttendanceInfo.builder() - .id(sessionWithAttendance.getid()) - .name(sessionWithAttendance.getname()) - .date(sessionWithAttendance.getdate()) - .attendee(sessionWithAttendance.getattendee()) - .absentee(sessionWithAttendance.getabsentee()) - .build(); - - } - - @Transactional(readOnly = true) - @Override - public void checkNotDeactivated(Long sessionId) { - Session session = sessionRepository.findById(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - if (session.isDeactivated()) { - throw new CurrentSessionDeactivatedException(); - } - } - - @Transactional(readOnly = true) - @Override - public Session get(Long sessionId) { - return sessionRepository.findById(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - } - - @Override - public void deactivate(Long sessionId) { - Session session = sessionRepository.findById(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - session.setDeactivated(true); - sessionRepository.save(session); - } - - public void setStartTime(Long sessionId, LocalDateTime currentTime) { - Session session = sessionRepository.findById(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - session.setAuthCodeCreatedAt(currentTime); - sessionRepository.save(session); - } - - -} diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index 1d371cc..491e8bf 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -1,8 +1,6 @@ package com.waruru.areyouhere.session.service.command; -import com.waruru.areyouhere.active.ActiveSessionService; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; -import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; import com.waruru.areyouhere.course.domain.entity.Course; diff --git a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java index 8cbefe7..aaaf981 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java @@ -2,9 +2,7 @@ import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.session.domain.entity.Session; -import com.waruru.areyouhere.active.domain.entity.SessionId; -import com.waruru.areyouhere.active.domain.repository.AuthCodeRedisRepository; -import com.waruru.areyouhere.active.domain.repository.SessionIdRedisRepository; +import com.waruru.areyouhere.active.domain.repository.ActiveSessionRepository; import com.waruru.areyouhere.session.domain.repository.SessionRepository; import com.waruru.areyouhere.session.domain.repository.dto.SessionInfo; import com.waruru.areyouhere.session.exception.CurrentSessionDeactivatedException; @@ -26,8 +24,7 @@ public class SessionQueryServiceImpl implements SessionQueryService { private final SessionRepository sessionRepository; - private final AuthCodeRedisRepository authCodeRedisRepository; - private final SessionIdRedisRepository sessionIdRedisRepository; + private final ActiveSessionRepository activeSessionRepository; @Override public CurrentSessionDto getCurrentSessionInfo(Long courseId) { @@ -111,18 +108,11 @@ private void throwIfSessionDeactivated(Session mostRecentSession) { } private CurrentSessionAttendanceInfo getAuthCodeIfExistsOrEmptyAuthCode(Long sessionId) { - SessionId session = sessionIdRedisRepository - .findById(sessionId) - .orElse(null); - - return session != null ? - authCodeRedisRepository - .findById(session.getAuthCode()) - .orElseThrow(CurrentSessionNotFoundException::new) - : CurrentSessionAttendanceInfo.builder() + return activeSessionRepository + .findBySessionId(sessionId).orElseGet(() -> CurrentSessionAttendanceInfo.builder() .authCode(null) .sessionName(null) - .build(); + .build()); } private List getRecentSessions(Long courseId) { From ff330f941d552e3cb11e437ebfaa9735e04dfdaf Mon Sep 17 00:00:00 2001 From: SHEOM Date: Thu, 18 Apr 2024 14:40:35 +0900 Subject: [PATCH 10/19] =?UTF-8?q?refactor:=20=EB=A9=94=EC=86=8C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EC=9D=BC=EA=B4=80=EC=84=B1=20=EC=9E=88=EA=B2=8C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#50)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eController.java => ActiveSessionController.java} | 8 ++++---- .../active/service/ActiveSessionService.java | 4 ++-- .../active/service/ActiveSessionServiceImpl.java | 4 ++-- .../course/controller/CourseController.java | 12 ++++++------ .../manager/controller/ManagerController.java | 2 +- .../areyouhere/manager/domain/entity/Manager.java | 4 ++-- .../areyouhere/manager/service/ManagerService.java | 2 +- .../manager/service/SessionManagerService.java | 2 +- .../session/controller/SessionController.java | 4 ++-- .../session/domain/repository/SessionRepository.java | 4 ++-- .../service/command/SessionCommandService.java | 2 -- .../service/command/SessionCommandServiceImpl.java | 10 +--------- .../service/query/SessionQueryServiceImpl.java | 4 ++-- 13 files changed, 26 insertions(+), 36 deletions(-) rename src/main/java/com/waruru/areyouhere/active/{ActiveSessionAttendanceController.java => ActiveSessionController.java} (83%) diff --git a/src/main/java/com/waruru/areyouhere/active/ActiveSessionAttendanceController.java b/src/main/java/com/waruru/areyouhere/active/ActiveSessionController.java similarity index 83% rename from src/main/java/com/waruru/areyouhere/active/ActiveSessionAttendanceController.java rename to src/main/java/com/waruru/areyouhere/active/ActiveSessionController.java index 5e265e1..f585a4d 100644 --- a/src/main/java/com/waruru/areyouhere/active/ActiveSessionAttendanceController.java +++ b/src/main/java/com/waruru/areyouhere/active/ActiveSessionController.java @@ -14,8 +14,8 @@ @RestController @RequiredArgsConstructor -@RequestMapping(ActiveSessionAttendanceController.AUTH_CODE_API_URL) -public class ActiveSessionAttendanceController { +@RequestMapping(ActiveSessionController.AUTH_CODE_API_URL) +public class ActiveSessionController { public static final String AUTH_CODE_API_URL = "/api/auth-code"; @@ -26,7 +26,7 @@ public class ActiveSessionAttendanceController { public ResponseEntity activate(@RequestBody AuthCodeRequestDto authCodeRequestDto) { Long sessionId = authCodeRequestDto.getSessionId(); Long courseId = authCodeRequestDto.getCourseId(); - return ResponseEntity.ok(activeSessionService.activateSession(sessionId, courseId)); + return ResponseEntity.ok(activeSessionService.activate(sessionId, courseId)); } @PostMapping("/deactivate") @@ -35,7 +35,7 @@ public ResponseEntity deactivate( Long sessionId = authCodeDeactivationRequestDto.getSessionId(); Long courseId = authCodeDeactivationRequestDto.getCourseId(); String authCode = authCodeDeactivationRequestDto.getAuthCode(); - activeSessionService.deactivateSession(authCode, sessionId, courseId); + activeSessionService.deactivate(authCode, sessionId, courseId); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java index e7d61c5..f15f847 100644 --- a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionService.java @@ -2,8 +2,8 @@ public interface ActiveSessionService { - public void deactivateSession(String authCode, Long sessionId, Long courseId); + public void deactivate(String authCode, Long sessionId, Long courseId); - public String activateSession(Long sessionId, Long courseId); + public String activate(Long sessionId, Long courseId); } diff --git a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java index 64a7abe..5ab1cd7 100644 --- a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java @@ -27,7 +27,7 @@ public class ActiveSessionServiceImpl implements ActiveSessionService { @Override @Transactional - public String activateSession(Long sessionId, Long courseId) { + public String activate(Long sessionId, Long courseId) { Course course = courseService.get(courseId); Session session = sessionQueryService.get(sessionId); LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); @@ -36,7 +36,7 @@ public String activateSession(Long sessionId, Long courseId) { @Override @Transactional - public void deactivateSession(String authCode, Long sessionId, Long courseId) { + public void deactivate(String authCode, Long sessionId, Long courseId) { sessionQueryService.checkNotDeactivated(sessionId); CurrentSessionAttendanceInfo currentSessionAttendanceInfo = activeAttendanceService.getSessionAttendanceInfoOrThrow( diff --git a/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java b/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java index 65f71b2..83e2c3b 100644 --- a/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java +++ b/src/main/java/com/waruru/areyouhere/course/controller/CourseController.java @@ -25,14 +25,14 @@ public class CourseController { @LoginRequired @GetMapping("/{courseId}") - ResponseEntity getCourse(@PathVariable Long courseId) { + ResponseEntity get(@PathVariable Long courseId) { Course course = courseService.get(courseId); return ResponseEntity.ok(CourseGetResponse.from(course)); } @LoginRequired @PostMapping - public ResponseEntity createCourse( + public ResponseEntity create( @Login Manager manager, @RequestBody CourseCreationRequest request) { courseService.create(manager.getId(), request.getName(), request.getDescription(), request.getAttendees(), @@ -43,7 +43,7 @@ public ResponseEntity createCourse( @LoginRequired @GetMapping - public ResponseEntity getAllCourses(@Login Manager manager) { + public ResponseEntity getAll(@Login Manager manager) { List courses = courseService.getAll(manager.getId()); AllCourseResponse response = new AllCourseResponse(courses); return ResponseEntity.ok(response); @@ -51,8 +51,8 @@ public ResponseEntity getAllCourses(@Login Manager manager) { @LoginRequired @PutMapping("/{courseId}") - public ResponseEntity updateCourse(@Login Manager manager, @PathVariable Long courseId, - @RequestBody CourseUpdateRequest request) { + public ResponseEntity update(@Login Manager manager, @PathVariable Long courseId, + @RequestBody CourseUpdateRequest request) { courseService.update(manager.getId(), courseId, request.getName(), request.getDescription(), request.isOnlyListNameAllowed()); return ResponseEntity.ok().build(); @@ -60,7 +60,7 @@ public ResponseEntity updateCourse(@Login Manager manager, @PathVariable L @LoginRequired @DeleteMapping("/{courseId}") - public ResponseEntity deleteCourse(@Login Manager manager + public ResponseEntity delete(@Login Manager manager , @PathVariable Long courseId) { courseService.delete(manager.getId(), courseId); return ResponseEntity.ok().build(); diff --git a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java index 261c19e..c855b7d 100644 --- a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java +++ b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java @@ -46,7 +46,7 @@ public ResponseEntity isLogin(@Login Manager manager){ @PostMapping("/signup") public ResponseEntity signUp(@RequestBody @Valid SignUpRequestDto signUpRequestDto){ - managerService.register(signUpRequestDto.getEmail(), signUpRequestDto.getPassword(), signUpRequestDto.getNickname()); + managerService.signUp(signUpRequestDto.getEmail(), signUpRequestDto.getPassword(), signUpRequestDto.getNickname()); return RESPONSE_OK; } diff --git a/src/main/java/com/waruru/areyouhere/manager/domain/entity/Manager.java b/src/main/java/com/waruru/areyouhere/manager/domain/entity/Manager.java index ef70093..0e815dd 100644 --- a/src/main/java/com/waruru/areyouhere/manager/domain/entity/Manager.java +++ b/src/main/java/com/waruru/areyouhere/manager/domain/entity/Manager.java @@ -20,10 +20,10 @@ public class Manager { private String email; @NotNull - private String password; + private String name; @NotNull - private String name; + private String password; @Builder public Manager(String email, String password, String name){ diff --git a/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java index dea2422..9c316c5 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java @@ -6,7 +6,7 @@ public interface ManagerService { public boolean login(String email, String password); - public void register(String email, String password, String nickname); + public void signUp(String email, String password, String nickname); public void logout(); diff --git a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java index 11c8e84..d246601 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java @@ -41,7 +41,7 @@ public void logout() { @Override @Transactional - public void register(String email, String password, String nickname){ + public void signUp(String email, String password, String nickname){ boolean isEmailDuplicated = isDuplicatedEmail(email); if(isEmailDuplicated){ diff --git a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java index 5541a67..8273c17 100644 --- a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java +++ b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java @@ -37,7 +37,7 @@ public class SessionController { // TODO : refactor => service Dto 그대로 사용. @GetMapping - public ResponseEntity getAllSession(@RequestParam("courseId") Long courseId){ + public ResponseEntity getAll(@RequestParam("courseId") Long courseId){ List allSessions = sessionQueryService.getAll(courseId); if(allSessions.isEmpty()){ @@ -65,7 +65,7 @@ public ResponseEntity delete(@RequestBody DeleteSessionRequestDto se public ResponseEntity getSessionBasicInfo(@PathVariable("sessionId") Long sessionId){ return ResponseEntity.ok(sessionQueryService.getSessionAttendanceInfo(sessionId)); } - + // TODO: refactor => attendeeService로 이동 @GetMapping("/{sessionId}/attendee") public ResponseEntity getSessionAllAttendees(@PathVariable("sessionId") Long sessionId){ List sessionAttendees = attendeeQueryService.getSessionAttendeesIfExistsOrEmpty( diff --git a/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java b/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java index 1832538..18ef14f 100644 --- a/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java +++ b/src/main/java/com/waruru/areyouhere/session/domain/repository/SessionRepository.java @@ -21,10 +21,10 @@ public interface SessionRepository extends JpaRepository{ @Query("SELECT s FROM session s WHERE s.course.id = :courseId order by s.createdAt desc limit 6") - public List findTOP6BySessionByCourseId(@Param("courseId") Long courseId); + public List findTOP6ByCourseId(@Param("courseId") Long courseId); @Query("SELECT s FROM session s WHERE s.course.id = :courseId order by s.createdAt desc limit 1") - public Optional findMostRecentSessionByCourseId(@Param("courseId") Long courseId); + public Optional findMostRecentByCourseId(@Param("courseId") Long courseId); //find attendee who participate particular course and no attendance in particular session by query diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java index 2c05607..24cb88e 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java @@ -11,7 +11,5 @@ public interface SessionCommandService { public void deactivate(Long sessionId); - public void setStartTime(Long sessionId, LocalDateTime currentTime); - public void updateAll(List sessions); } diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index 491e8bf..90815a7 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -12,7 +12,6 @@ import com.waruru.areyouhere.session.exception.CurrentSessionNotFoundException; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; import com.waruru.areyouhere.session.service.dto.UpdateSession; -import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -33,7 +32,7 @@ public void create(Long courseId, String sessionName) { Course course = courseRepository.findById(courseId) .orElseThrow(CourseNotFoundException::new); - sessionRepository.findMostRecentSessionByCourseId(courseId) + sessionRepository.findMostRecentByCourseId(courseId) .ifPresent(session -> { if (!session.isDeactivated()) { throw new ActivatedSessionExistsException(); @@ -69,13 +68,6 @@ public void deactivate(Long sessionId) { sessionRepository.save(session); } - @Override - public void setStartTime(Long sessionId, LocalDateTime currentTime) { - Session session = sessionRepository.findById(sessionId) - .orElseThrow(SessionIdNotFoundException::new); - session.setAuthCodeCreatedAt(currentTime); - sessionRepository.save(session); - } @Override public void updateAll(List sessions) { diff --git a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java index aaaf981..7924793 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/query/SessionQueryServiceImpl.java @@ -29,7 +29,7 @@ public class SessionQueryServiceImpl implements SessionQueryService { @Override public CurrentSessionDto getCurrentSessionInfo(Long courseId) { Session mostRecentSession = sessionRepository - .findMostRecentSessionByCourseId(courseId) + .findMostRecentByCourseId(courseId) .orElseThrow(CurrentSessionNotFoundException::new); // 제일 최근 세션이 이미 출석 체크가 끝났는지 @@ -116,7 +116,7 @@ private CurrentSessionAttendanceInfo getAuthCodeIfExistsOrEmptyAuthCode(Long ses } private List getRecentSessions(Long courseId) { - return Optional.ofNullable(sessionRepository.findTOP6BySessionByCourseId(courseId)) + return Optional.ofNullable(sessionRepository.findTOP6ByCourseId(courseId)) .orElse(Collections.emptyList()); } From 2b3b73ab17d9b377c624341a22075da7eb317508 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Fri, 19 Apr 2024 20:59:22 +0900 Subject: [PATCH 11/19] =?UTF-8?q?Feat/Manager=20Manager=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20(#51)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../manager/controller/ManagerController.java | 8 ++++++++ .../manager/domain/repository/ManagerRepository.java | 2 ++ .../areyouhere/manager/service/ManagerService.java | 2 ++ .../manager/service/SessionManagerService.java | 11 +++++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java index c855b7d..706f0c3 100644 --- a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java +++ b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java @@ -18,6 +18,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -88,4 +89,11 @@ public ResponseEntity update(@RequestBody UpdateRequestDto updateReq return RESPONSE_OK; } + @LoginRequired + @DeleteMapping + public ResponseEntity delete(@Login Manager manager){ + managerService.delete(manager.getId()); + return RESPONSE_OK; + } + } diff --git a/src/main/java/com/waruru/areyouhere/manager/domain/repository/ManagerRepository.java b/src/main/java/com/waruru/areyouhere/manager/domain/repository/ManagerRepository.java index f3a2556..9ec6b5e 100644 --- a/src/main/java/com/waruru/areyouhere/manager/domain/repository/ManagerRepository.java +++ b/src/main/java/com/waruru/areyouhere/manager/domain/repository/ManagerRepository.java @@ -10,4 +10,6 @@ public interface ManagerRepository extends JpaRepository { public boolean existsByEmail(String email); + public void deleteById(Long id); + } diff --git a/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java index 9c316c5..582f5ad 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java @@ -15,4 +15,6 @@ public interface ManagerService { public boolean isDuplicatedEmail(String email); public void update(Long userId, String name, String password); + + public void delete(Long userId); } diff --git a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java index d246601..7848919 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java @@ -2,6 +2,9 @@ import com.waruru.areyouhere.auth.entity.LoginUser; import com.waruru.areyouhere.auth.session.SessionManager; +import com.waruru.areyouhere.common.annotation.LoginRequired; +import com.waruru.areyouhere.course.domain.repository.CourseRepository; +import com.waruru.areyouhere.course.service.CourseService; import com.waruru.areyouhere.manager.domain.entity.Manager; import com.waruru.areyouhere.manager.domain.repository.ManagerRepository; import com.waruru.areyouhere.manager.exception.DuplicatedEmailException; @@ -17,7 +20,9 @@ @RequiredArgsConstructor @Slf4j public class SessionManagerService implements ManagerService { - + // TODO: refactor: 계층 구조 최초 위반 -> 그냥 soft delete로 바꾸기 + private final CourseService courseService; + private final CourseRepository courseRepository; private final ManagerRepository managerRepository; private final SessionManager sessionManager; private final PasswordEncoder passwordEncoder; @@ -85,8 +90,10 @@ public void update(Long userId, String name, String password){ managerRepository.save(manager.update(name, passwordEncoder.encode(password))); } + @Override + @Transactional public void delete(Long userId){ - + courseRepository.findAllByManagerId(userId).forEach(course -> courseService.delete(userId, course.getId())); managerRepository.deleteById(userId); } } From 3a4c3b5d5d82020c3b6e92783f6f6ff50bccbc6d Mon Sep 17 00:00:00 2001 From: SHEOM Date: Fri, 19 Apr 2024 21:20:29 +0900 Subject: [PATCH 12/19] =?UTF-8?q?Feat/Session:=20=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94=EB=90=98=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=84=B8?= =?UTF-8?q?=EC=85=98=20=EC=82=AD=EC=A0=9C=20API=20(#53)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/controller/SessionController.java | 20 ++++++++++++++----- .../command/SessionCommandService.java | 2 ++ .../command/SessionCommandServiceImpl.java | 12 +++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java index 8273c17..432259d 100644 --- a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java +++ b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java @@ -3,6 +3,7 @@ import com.waruru.areyouhere.attendee.service.dto.SessionAttendees; import com.waruru.areyouhere.attendee.service.query.AttendeeQueryService; +import com.waruru.areyouhere.common.annotation.LoginRequired; import com.waruru.areyouhere.session.dto.request.CreateSessionRequestDto; import com.waruru.areyouhere.session.dto.request.DeleteSessionRequestDto; import com.waruru.areyouhere.session.dto.request.UpdateSessionsRequestDto; @@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -36,6 +38,7 @@ public class SessionController { private final AttendeeQueryService attendeeQueryService; // TODO : refactor => service Dto 그대로 사용. + @LoginRequired @GetMapping public ResponseEntity getAll(@RequestParam("courseId") Long courseId){ @@ -48,24 +51,31 @@ public ResponseEntity getAll(@RequestParam("courseId") .allSessionAttendanceInfo(allSessions) .build()); } - + @LoginRequired @PostMapping public ResponseEntity create(@RequestBody CreateSessionRequestDto createSessionRequestDto){ sessionCommandService.create(createSessionRequestDto.getCourseId(), createSessionRequestDto.getSessionName()); return ResponseEntity.ok().build(); } - + @LoginRequired @PostMapping("/delete") public ResponseEntity delete(@RequestBody DeleteSessionRequestDto sessionIds){ sessionCommandService.deleteAll(sessionIds.getSessionIds()); return ResponseEntity.ok().build(); } - + @LoginRequired + @DeleteMapping + public ResponseEntity deleteNotActivated(@RequestParam("courseId") Long courseId){ + sessionCommandService.deleteNotActivated(courseId); + return ResponseEntity.ok().build(); + } + @LoginRequired @GetMapping("/{sessionId}") public ResponseEntity getSessionBasicInfo(@PathVariable("sessionId") Long sessionId){ return ResponseEntity.ok(sessionQueryService.getSessionAttendanceInfo(sessionId)); } // TODO: refactor => attendeeService로 이동 + @LoginRequired @GetMapping("/{sessionId}/attendee") public ResponseEntity getSessionAllAttendees(@PathVariable("sessionId") Long sessionId){ List sessionAttendees = attendeeQueryService.getSessionAttendeesIfExistsOrEmpty( @@ -75,7 +85,7 @@ public ResponseEntity getSessionAllAttendees(@PathV .sessionAttendees(sessionAttendees) .build()); } - + @LoginRequired @GetMapping("/{sessionId}/absentee") public ResponseEntity getSessionAbsenteeOnly(@PathVariable("sessionId") Long sessionId){ List sessionAttendees = attendeeQueryService.getSessionAbsenteesIfExistsOrEmpty( @@ -85,7 +95,7 @@ public ResponseEntity getSessionAbsenteeOnly(@PathV .sessionAttendees(sessionAttendees) .build()); } - + @LoginRequired @PutMapping public ResponseEntity updateAll(@RequestBody UpdateSessionsRequestDto updateSessionsRequestDto){ sessionCommandService.updateAll(updateSessionsRequestDto.getSessions()); diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java index 24cb88e..f84b698 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java @@ -7,6 +7,8 @@ public interface SessionCommandService { public void create(Long courseId, String sessionName); + public void deleteNotActivated(Long courseId); + public void deleteAll(List sessionIds); public void deactivate(Long sessionId); diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index 90815a7..86edb1b 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -1,5 +1,6 @@ package com.waruru.areyouhere.session.service.command; +import com.waruru.areyouhere.active.service.ActiveAttendanceService; import com.waruru.areyouhere.attendance.domain.repository.AttendanceRepository; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; @@ -26,7 +27,9 @@ public class SessionCommandServiceImpl implements SessionCommandService { private final CourseRepository courseRepository; private final AttendanceRepository attendanceRepository; private final AttendeeRepository attendeeRepository; + private final ActiveAttendanceService activeAttendanceService; + @Override public void create(Long courseId, String sessionName) { // TODO : exception 수정 Course course = courseRepository.findById(courseId) @@ -51,6 +54,15 @@ public void create(Long courseId, String sessionName) { sessionRepository.save(session); } + @Override + public void deleteNotActivated(Long courseId) { + sessionRepository.findMostRecentByCourseId(courseId) + .ifPresent(session -> { + if (!activeAttendanceService.isSessionActivatedByCourseId(courseId) && !session.isDeactivated()) { + sessionRepository.delete(session); + } + }); + } @Override public void deleteAll(List sessionIds) { sessionIds.forEach(sessionId -> { From ae8c87653dc28fa7b372a11aa50bfd3672a5ad8c Mon Sep 17 00:00:00 2001 From: SHEOM Date: Sat, 27 Apr 2024 14:11:32 +0900 Subject: [PATCH 13/19] =?UTF-8?q?Feat/email=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EC=84=9C=EB=B9=84=EC=8A=A4=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/develop.yaml | 4 + .github/workflows/release.yaml | 4 + build.gradle | 1 + .../service/ActiveAttendanceServiceImpl.java | 2 +- .../areyouhere/common/config/EmailConfig.java | 44 +++++++++++ .../areyouhere/common/config/RedisConfig.java | 17 ++-- .../common/config/UtilityConfig.java | 4 +- .../{ => random}/AlphanumericIdGenerator.java | 2 +- .../RandomIdentifierGenerator.java | 2 +- .../email/domain/MessageHolder.java | 15 ++++ .../email/domain/MessageTemplate.java | 16 ++++ .../email/service/EmailService.java | 8 ++ .../email/service/JavaEmailServiceImpl.java | 40 ++++++++++ .../manager/controller/ManagerController.java | 54 +++++++++---- .../repository/VerifyCodeRepository.java | 41 ++++++++++ .../dto/request/ResetPasswordRequestDto.java | 20 +++++ .../manager/dto/request/SignUpRequestDto.java | 4 +- .../dto/request/VerifyEmailRequestDto.java | 17 ++++ .../manager/service/ManagerService.java | 8 ++ .../service/SessionManagerService.java | 77 +++++++++++++++---- .../session/controller/SessionController.java | 1 + src/main/resources/application-dev.yaml | 13 +++- src/main/resources/application-local.yaml | 15 +++- src/main/resources/application-release.yaml | 16 +++- 24 files changed, 375 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java rename src/main/java/com/waruru/areyouhere/common/utils/{ => random}/AlphanumericIdGenerator.java (92%) rename src/main/java/com/waruru/areyouhere/common/utils/{ => random}/RandomIdentifierGenerator.java (65%) create mode 100644 src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java create mode 100644 src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java create mode 100644 src/main/java/com/waruru/areyouhere/email/service/EmailService.java create mode 100644 src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java create mode 100644 src/main/java/com/waruru/areyouhere/manager/domain/repository/VerifyCodeRepository.java create mode 100644 src/main/java/com/waruru/areyouhere/manager/dto/request/ResetPasswordRequestDto.java create mode 100644 src/main/java/com/waruru/areyouhere/manager/dto/request/VerifyEmailRequestDto.java diff --git a/.github/workflows/develop.yaml b/.github/workflows/develop.yaml index 9ff5edb..ed02940 100644 --- a/.github/workflows/develop.yaml +++ b/.github/workflows/develop.yaml @@ -39,6 +39,10 @@ jobs: spring.datasource.password: ${{ secrets.MYSQL_DATASOURCE_PASSWORD }} spring.data.redis.host: ${{ secrets.REDIS_DATASOURCE_HOST }} spring.data.redis.port: ${{ secrets.REDIS_DATASOURCE_PORT }} + spring.mail.host: ${{ secrets.DEV_MAIL_HOST }} + spring.mail.username: ${{ secrets.DEV_MAIL_USERNAME }} + spring.mail.password: ${{ secrets.DEV_MAIL_PASSWORD }} + spring.mail.from: ${{ secrets.DEV_MAIL_SENDER }} cookie.encode: ${{ secrets.SECRET_KEY }} - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ae982e3..7527f2d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -36,6 +36,10 @@ jobs: spring.datasource.password: ${{ secrets.MYSQL_DATASOURCE_PASSWORD }} spring.data.redis.host: ${{ secrets.REDIS_DATASOURCE_HOST }} spring.data.redis.port: ${{ secrets.REDIS_DATASOURCE_PORT }} + spring.mail.host: ${{ secrets.RELEASE_MAIL_HOST }} + spring.mail.username: ${{ secrets.RELEASE_MAIL_USERNAME }} + spring.mail.password: ${{ secrets.RELEASE_MAIL_PASSWORD }} + spring.mail.from: ${{ secrets.RELEASE_MAIL_SENDER }} cookie.encode: ${{ secrets.SECRET_KEY }} - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/build.gradle b/build.gradle index cb8a588..2c7196b 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation "org.springframework.boot:spring-boot-starter-security" + implementation 'org.springframework.boot:spring-boot-starter-mail' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceServiceImpl.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceServiceImpl.java index 6d71a62..058e590 100644 --- a/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveAttendanceServiceImpl.java @@ -5,7 +5,7 @@ import com.waruru.areyouhere.attendee.domain.entity.Attendee; import com.waruru.areyouhere.attendee.domain.repository.AttendeeRepository; import com.waruru.areyouhere.attendee.service.dto.AttendeeInfo; -import com.waruru.areyouhere.common.utils.RandomIdentifierGenerator; +import com.waruru.areyouhere.common.utils.random.RandomIdentifierGenerator; import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.active.domain.entity.CurrentSessionAttendanceInfo; import com.waruru.areyouhere.session.domain.entity.Session; diff --git a/src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java b/src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java new file mode 100644 index 0000000..ecd4708 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java @@ -0,0 +1,44 @@ +package com.waruru.areyouhere.common.config; + +import java.util.Properties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; + + +@Configuration +@ConfigurationProperties(prefix = "spring.mail") +public class EmailConfig { + private String username; + private String password; + private String host; + private int port; + + @Profile({"develop", "release"}) + @Bean + public JavaMailSender getJavaMailSender() { + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(host); + mailSender.setUsername(username); + mailSender.setPassword(password); + mailSender.setPort(port); + + Properties javaMailProperties = new Properties(); + javaMailProperties.put("mail.smtp.auth", "true"); + javaMailProperties.put("mail.smtp.starttls.enable", "true"); + javaMailProperties.put("mail.smtp.starttls.required", "true"); + + mailSender.setJavaMailProperties(javaMailProperties); + + return mailSender; + } + + @Profile("local") + @Bean + public JavaMailSender getLocalJavaMailSender() { + return new JavaMailSenderImpl(); + } +} diff --git a/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java b/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java index e846bf7..a5e0b95 100644 --- a/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java +++ b/src/main/java/com/waruru/areyouhere/common/config/RedisConfig.java @@ -32,15 +32,14 @@ public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(redisStandaloneConfiguration); } -// @Bean -// public RedisTemplate redisTemplate() { -// RedisTemplate redisTemplate = new RedisTemplate<>(); -// redisTemplate.setConnectionFactory(redisConnectionFactory()); -// redisTemplate.setKeySerializer( new StringRedisSerializer() ); -// redisTemplate.setHashValueSerializer( new GenericToStringSerializer< Long >( Long.class ) ); -// redisTemplate.setValueSerializer( new GenericToStringSerializer< Long >( Long.class ) ); -// return redisTemplate; -// } + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + return redisTemplate; + } } diff --git a/src/main/java/com/waruru/areyouhere/common/config/UtilityConfig.java b/src/main/java/com/waruru/areyouhere/common/config/UtilityConfig.java index 3ea033f..0085936 100644 --- a/src/main/java/com/waruru/areyouhere/common/config/UtilityConfig.java +++ b/src/main/java/com/waruru/areyouhere/common/config/UtilityConfig.java @@ -1,7 +1,7 @@ package com.waruru.areyouhere.common.config; -import com.waruru.areyouhere.common.utils.AlphanumericIdGenerator; -import com.waruru.areyouhere.common.utils.RandomIdentifierGenerator; +import com.waruru.areyouhere.common.utils.random.AlphanumericIdGenerator; +import com.waruru.areyouhere.common.utils.random.RandomIdentifierGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/waruru/areyouhere/common/utils/AlphanumericIdGenerator.java b/src/main/java/com/waruru/areyouhere/common/utils/random/AlphanumericIdGenerator.java similarity index 92% rename from src/main/java/com/waruru/areyouhere/common/utils/AlphanumericIdGenerator.java rename to src/main/java/com/waruru/areyouhere/common/utils/random/AlphanumericIdGenerator.java index 3188569..4d82909 100644 --- a/src/main/java/com/waruru/areyouhere/common/utils/AlphanumericIdGenerator.java +++ b/src/main/java/com/waruru/areyouhere/common/utils/random/AlphanumericIdGenerator.java @@ -1,4 +1,4 @@ -package com.waruru.areyouhere.common.utils; +package com.waruru.areyouhere.common.utils.random; import java.util.Random; diff --git a/src/main/java/com/waruru/areyouhere/common/utils/RandomIdentifierGenerator.java b/src/main/java/com/waruru/areyouhere/common/utils/random/RandomIdentifierGenerator.java similarity index 65% rename from src/main/java/com/waruru/areyouhere/common/utils/RandomIdentifierGenerator.java rename to src/main/java/com/waruru/areyouhere/common/utils/random/RandomIdentifierGenerator.java index b32b6b3..2c36a88 100644 --- a/src/main/java/com/waruru/areyouhere/common/utils/RandomIdentifierGenerator.java +++ b/src/main/java/com/waruru/areyouhere/common/utils/random/RandomIdentifierGenerator.java @@ -1,4 +1,4 @@ -package com.waruru.areyouhere.common.utils; +package com.waruru.areyouhere.common.utils.random; public interface RandomIdentifierGenerator { String generateRandomIdentifier(int length); diff --git a/src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java b/src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java new file mode 100644 index 0000000..90b1d18 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java @@ -0,0 +1,15 @@ +package com.waruru.areyouhere.email.domain; + +import lombok.Getter; + +@Getter +public class MessageHolder { + private String title; + + private String contents; + + public MessageHolder(String title, MessageTemplate messageTemplate, Object... values){ + this.title = title; + this.contents = String.format(messageTemplate.getTemplate(), (Object) values); + } +} diff --git a/src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java b/src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java new file mode 100644 index 0000000..1668271 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java @@ -0,0 +1,16 @@ +package com.waruru.areyouhere.email.domain; + +public enum MessageTemplate { + PASSWORD_RESET("You can reset password by this link: %s"), + SIGN_UP("You can verify your email by this link: %s"); + + private final String template; + + MessageTemplate(String template) { + this.template = template; + } + + public String getTemplate() { + return template; + } +} diff --git a/src/main/java/com/waruru/areyouhere/email/service/EmailService.java b/src/main/java/com/waruru/areyouhere/email/service/EmailService.java new file mode 100644 index 0000000..7f2fa57 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/email/service/EmailService.java @@ -0,0 +1,8 @@ +package com.waruru.areyouhere.email.service; + + +import com.waruru.areyouhere.email.domain.MessageTemplate; + +public interface EmailService { + public void sendVerifyEmail(String to, String title, String verificationLink, MessageTemplate messageTemplate); +} diff --git a/src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java b/src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java new file mode 100644 index 0000000..3d28efa --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java @@ -0,0 +1,40 @@ +package com.waruru.areyouhere.email.service; + +import com.waruru.areyouhere.email.domain.MessageHolder; +import com.waruru.areyouhere.email.domain.MessageTemplate; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +@Slf4j +public class JavaEmailServiceImpl implements EmailService { + private final JavaMailSender emailSender; + + @Value("${spring.mail.from}") + private String from; + + + public void sendVerifyEmail(String to, String title, String verificationLink, MessageTemplate messageTemplate) { + MessageHolder messageHolder = new MessageHolder(title, messageTemplate, verificationLink); + sendSimpleMessage(to, messageHolder.getTitle(), messageHolder.getContents()); + } + + private void sendSimpleMessage(String to, String title, String content) { + if (from == null || from.isEmpty()) { + log.info("Email text Test: " + content); + return; + } + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(from); + message.setTo(to); + message.setSubject(title); + message.setText(content); + emailSender.send(message); + } + +} diff --git a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java index 706f0c3..9fd61b3 100644 --- a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java +++ b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java @@ -9,8 +9,10 @@ import com.waruru.areyouhere.common.annotation.LoginRequired; import com.waruru.areyouhere.manager.domain.entity.Manager; import com.waruru.areyouhere.manager.dto.request.LoginRequestDto; +import com.waruru.areyouhere.manager.dto.request.ResetPasswordRequestDto; import com.waruru.areyouhere.manager.dto.request.SignUpRequestDto; import com.waruru.areyouhere.manager.dto.request.UpdateRequestDto; +import com.waruru.areyouhere.manager.dto.request.VerifyEmailRequestDto; import com.waruru.areyouhere.manager.dto.response.ManagerDto; import com.waruru.areyouhere.manager.service.ManagerService; import jakarta.validation.Valid; @@ -37,25 +39,25 @@ public class ManagerController { @LoginRequired @GetMapping("/me") - public ResponseEntity isLogin(@Login Manager manager){ + public ResponseEntity isLogin(@Login Manager manager) { return ResponseEntity.ok(ManagerDto.builder() - .email(manager.getEmail()) - .name(manager.getName()) + .email(manager.getEmail()) + .name(manager.getName()) .build()); } @PostMapping("/signup") - public ResponseEntity signUp(@RequestBody @Valid SignUpRequestDto signUpRequestDto){ + public ResponseEntity signUp(@RequestBody @Valid SignUpRequestDto signUpRequestDto) { - managerService.signUp(signUpRequestDto.getEmail(), signUpRequestDto.getPassword(), signUpRequestDto.getNickname()); + managerService.signUp(signUpRequestDto.getEmail(), signUpRequestDto.getPassword(), signUpRequestDto.getName()); return RESPONSE_OK; } @PostMapping("/login") - public ResponseEntity login(@RequestBody @Valid LoginRequestDto loginRequestDto){ + public ResponseEntity login(@RequestBody @Valid LoginRequestDto loginRequestDto) { - if(managerService.login(loginRequestDto.getEmail(), loginRequestDto.getPassword())){ + if (managerService.login(loginRequestDto.getEmail(), loginRequestDto.getPassword())) { return RESPONSE_OK; } @@ -64,36 +66,62 @@ public ResponseEntity login(@RequestBody @Valid LoginRequestDto logi @LoginRequired @GetMapping("/logout") - public ResponseEntity logout(){ + public ResponseEntity logout() { managerService.logout(); return RESPONSE_OK; } @GetMapping("/email-availability") - public ResponseEntity isDuplicatedEmail(@RequestParam String email){ - if(managerService.isDuplicatedEmail(email)){ + public ResponseEntity isDuplicatedEmail(@RequestParam String email) { + if (managerService.isDuplicatedEmail(email)) { return RESPONSE_CONFLICT; } return RESPONSE_OK; } @GetMapping("/unauthorized") - public ResponseEntity unauthorized(){ + public ResponseEntity unauthorized() { return RESPONSE_FORBIDDEN; } @LoginRequired @PutMapping - public ResponseEntity update(@RequestBody UpdateRequestDto updateRequestDto, @Login Manager manager){ + public ResponseEntity update(@RequestBody UpdateRequestDto updateRequestDto, @Login Manager manager) { managerService.update(manager.getId(), updateRequestDto.getName(), updateRequestDto.getPassword()); return RESPONSE_OK; } @LoginRequired @DeleteMapping - public ResponseEntity delete(@Login Manager manager){ + public ResponseEntity delete(@Login Manager manager) { managerService.delete(manager.getId()); return RESPONSE_OK; } + @GetMapping("/email") + public ResponseEntity sendSignUpEmail(@RequestParam String email) { + managerService.sendEmailForSignUp(email); + return RESPONSE_BAD_REQUEST; + } + + @GetMapping("/password") + public ResponseEntity sendPasswordEmail(@RequestParam String email) { + managerService.sendEmailForPasswordReset(email); + return RESPONSE_BAD_REQUEST; + } + + @PostMapping("/verification") + public ResponseEntity verifyEmail(@RequestBody @Valid VerifyEmailRequestDto verifyEmailRequestDto) { + managerService.verifyEmail(verifyEmailRequestDto.getEmail(), verifyEmailRequestDto.getCode()); + return RESPONSE_OK; + } + + @PostMapping("/password") + public ResponseEntity resetPassword( + @RequestBody @Valid ResetPasswordRequestDto resetPasswordRequestDto) { + managerService.resetPassword(resetPasswordRequestDto.getEmail(), resetPasswordRequestDto.getPassword()); + return RESPONSE_OK; + } + + } diff --git a/src/main/java/com/waruru/areyouhere/manager/domain/repository/VerifyCodeRepository.java b/src/main/java/com/waruru/areyouhere/manager/domain/repository/VerifyCodeRepository.java new file mode 100644 index 0000000..858476c --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/manager/domain/repository/VerifyCodeRepository.java @@ -0,0 +1,41 @@ +package com.waruru.areyouhere.manager.domain.repository; + +import com.waruru.areyouhere.common.utils.random.RandomIdentifierGenerator; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class VerifyCodeRepository { + private final RedisTemplate redisTemplate; + private final RandomIdentifierGenerator randomIdentifierGenerator; + + private final String VERIFIED = "verified"; + + public String saveAndGetCode(String email) { + String verificationCode = randomIdentifierGenerator.generateRandomIdentifier(6); + redisTemplate.opsForValue().set(email, verificationCode); + redisTemplate.opsForValue().getAndExpire(email, 10, TimeUnit.MINUTES); + return verificationCode; + } + + public void saveVerification(String email) { + redisTemplate.opsForValue().set(email, VERIFIED); + redisTemplate.opsForValue().getAndExpire(email, 30, TimeUnit.MINUTES); + } + + public String findByEmail(String email) { + return redisTemplate.opsForValue().get(email); + } + + public void deleteByEmail(String email) { + redisTemplate.delete(email); + } + + public boolean isVerified(String email) { + String verifyCode = redisTemplate.opsForValue().get(email); + return verifyCode != null && verifyCode.equals(VERIFIED); + } +} diff --git a/src/main/java/com/waruru/areyouhere/manager/dto/request/ResetPasswordRequestDto.java b/src/main/java/com/waruru/areyouhere/manager/dto/request/ResetPasswordRequestDto.java new file mode 100644 index 0000000..941ee28 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/manager/dto/request/ResetPasswordRequestDto.java @@ -0,0 +1,20 @@ +package com.waruru.areyouhere.manager.dto.request; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import lombok.Getter; + +@Getter +public class ResetPasswordRequestDto { + + @NotEmpty + @Email(message = "유효하지 않은 이메일 형식입니다.", + regexp = "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$") + String email; + + @NotEmpty + @Pattern(message = "비밀 번호는 영문과 특수 문자, 숫자를 포함하여 8자 이상이어야 합니다.", + regexp = "^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[\\W_]).{8,20}$") + String password; +} diff --git a/src/main/java/com/waruru/areyouhere/manager/dto/request/SignUpRequestDto.java b/src/main/java/com/waruru/areyouhere/manager/dto/request/SignUpRequestDto.java index 9c3eef3..5c22745 100644 --- a/src/main/java/com/waruru/areyouhere/manager/dto/request/SignUpRequestDto.java +++ b/src/main/java/com/waruru/areyouhere/manager/dto/request/SignUpRequestDto.java @@ -1,7 +1,6 @@ package com.waruru.areyouhere.manager.dto.request; -import com.waruru.areyouhere.manager.domain.entity.Manager; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Pattern; @@ -10,7 +9,6 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.security.crypto.password.PasswordEncoder; @Getter @@ -32,5 +30,5 @@ public class SignUpRequestDto { @NotEmpty @Pattern(message = "닉네임은 2자 이상 16자 이하의 영어, 숫자, 한글로 입력해주세요. 초성은 허가하지 않습니다.", regexp = "^(?=.*[a-z0-9가-힣])[a-z0-9가-힣]{2,16}$") - private String nickname; + private String name; } diff --git a/src/main/java/com/waruru/areyouhere/manager/dto/request/VerifyEmailRequestDto.java b/src/main/java/com/waruru/areyouhere/manager/dto/request/VerifyEmailRequestDto.java new file mode 100644 index 0000000..b914b2f --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/manager/dto/request/VerifyEmailRequestDto.java @@ -0,0 +1,17 @@ +package com.waruru.areyouhere.manager.dto.request; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotEmpty; +import lombok.Getter; + +@Getter +public class VerifyEmailRequestDto { + + @NotEmpty + String code; + + @Email(message = "유효하지 않은 이메일 형식입니다.", + regexp = "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$") + @NotEmpty + String email; +} diff --git a/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java index 582f5ad..52c5688 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/ManagerService.java @@ -17,4 +17,12 @@ public interface ManagerService { public void update(Long userId, String name, String password); public void delete(Long userId); + + public void sendEmailForSignUp(String email); + + public void sendEmailForPasswordReset(String email); + + public void verifyEmail(String email, String verificationCode); + + public void resetPassword(String email, String password); } diff --git a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java index 7848919..e06c237 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java @@ -2,15 +2,16 @@ import com.waruru.areyouhere.auth.entity.LoginUser; import com.waruru.areyouhere.auth.session.SessionManager; -import com.waruru.areyouhere.common.annotation.LoginRequired; +import com.waruru.areyouhere.email.domain.MessageTemplate; +import com.waruru.areyouhere.email.service.EmailService; import com.waruru.areyouhere.course.domain.repository.CourseRepository; import com.waruru.areyouhere.course.service.CourseService; import com.waruru.areyouhere.manager.domain.entity.Manager; import com.waruru.areyouhere.manager.domain.repository.ManagerRepository; +import com.waruru.areyouhere.manager.domain.repository.VerifyCodeRepository; import com.waruru.areyouhere.manager.exception.DuplicatedEmailException; import com.waruru.areyouhere.manager.exception.UnAuthenticatedException; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -18,21 +19,28 @@ @Service @RequiredArgsConstructor -@Slf4j public class SessionManagerService implements ManagerService { - // TODO: refactor: 계층 구조 최초 위반 -> 그냥 soft delete로 바꾸기 + // TODO: refactor: 계층 구조 위반 private final CourseService courseService; + private final EmailService emailService; + private final CourseRepository courseRepository; private final ManagerRepository managerRepository; + private final VerifyCodeRepository verifyCodeRepository; + private final SessionManager sessionManager; private final PasswordEncoder passwordEncoder; + private static final String SIGNUP_EMAIL_TITLE = "이메일 인증"; + private static final String PASSWORD_RESET_EMAIL_TITLE = "비밀번호 재설정"; + + @Override @Transactional(readOnly = true) public boolean login(String email, String password) { Manager findManager = managerRepository.findManagerByEmail(email) .orElseThrow(UnAuthenticatedException::new); - if(passwordEncoder.matches(password, findManager.getPassword())){ + if (passwordEncoder.matches(password, findManager.getPassword())) { sessionManager.createSession(findManager.getId()); return true; } @@ -46,10 +54,14 @@ public void logout() { @Override @Transactional - public void signUp(String email, String password, String nickname){ + public void signUp(String email, String password, String nickname) { boolean isEmailDuplicated = isDuplicatedEmail(email); - if(isEmailDuplicated){ + if (!verifyCodeRepository.isVerified(email)) { + throw new UnAuthenticatedException("이메일 인증을 완료해주세요."); + } + + if (isEmailDuplicated) { throw new DuplicatedEmailException("중복된 이메일입니다."); } Manager manager = managerRepository.save( @@ -60,16 +72,16 @@ public void signUp(String email, String password, String nickname){ .build() ); - + verifyCodeRepository.deleteByEmail(email); sessionManager.createSession(manager.getId()); } @Override @Transactional(readOnly = true) - public Manager getLoginUser(){ + public Manager getLoginUser() { LoginUser loginUser = sessionManager.getSession(); - if (loginUser == null){ + if (loginUser == null) { throw new UnAuthenticatedException(); } @@ -78,22 +90,61 @@ public Manager getLoginUser(){ @Override @Transactional(readOnly = true) - public boolean isDuplicatedEmail(String email){ + public boolean isDuplicatedEmail(String email) { return managerRepository.existsByEmail(email); } @Override @Transactional - public void update(Long userId, String name, String password){ + public void update(Long userId, String name, String password) { Manager manager = managerRepository.findById(userId).orElseThrow(UnAuthenticatedException::new); managerRepository.save(manager.update(name, passwordEncoder.encode(password))); } @Override @Transactional - public void delete(Long userId){ + public void delete(Long userId) { courseRepository.findAllByManagerId(userId).forEach(course -> courseService.delete(userId, course.getId())); + sessionManager.removeSession(); managerRepository.deleteById(userId); } + + @Override + @Transactional + public void sendEmailForSignUp(String email) { + String verificationCode = verifyCodeRepository.saveAndGetCode(email); + emailService.sendVerifyEmail(email, SIGNUP_EMAIL_TITLE, verificationCode, MessageTemplate.SIGN_UP); + } + + @Override + @Transactional + public void sendEmailForPasswordReset(String email) { + String verificationCode = verifyCodeRepository.saveAndGetCode(email); + emailService.sendVerifyEmail(email, PASSWORD_RESET_EMAIL_TITLE, verificationCode, + MessageTemplate.PASSWORD_RESET); + } + + @Override + @Transactional + public void verifyEmail(String email, String verificationCode) { + String savedCode = verifyCodeRepository.findByEmail(email); + if (savedCode == null || !savedCode.equals(verificationCode)) { + throw new UnAuthenticatedException("인증코드가 일치하지 않습니다."); + } + verifyCodeRepository.deleteByEmail(email); + verifyCodeRepository.saveVerification(email); + } + + @Override + @Transactional + public void resetPassword(String email, String password) { + if (!verifyCodeRepository.isVerified(email)) { + throw new UnAuthenticatedException("이메일 인증을 완료해주세요."); + } + Manager manager = managerRepository.findManagerByEmail(email).orElseThrow(UnAuthenticatedException::new); + managerRepository.save(manager.update(manager.getName(), passwordEncoder.encode(password))); + verifyCodeRepository.deleteByEmail(email); + } + } diff --git a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java index 432259d..3a9a40b 100644 --- a/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java +++ b/src/main/java/com/waruru/areyouhere/session/controller/SessionController.java @@ -69,6 +69,7 @@ public ResponseEntity deleteNotActivated(@RequestParam("courseId") L sessionCommandService.deleteNotActivated(courseId); return ResponseEntity.ok().build(); } + @LoginRequired @GetMapping("/{sessionId}") public ResponseEntity getSessionBasicInfo(@PathVariable("sessionId") Long sessionId){ diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index dbf782b..6e41b16 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -19,11 +19,22 @@ spring: redis: host: ${REDIS_DATASOURCE_HOST} port: ${REDIS_DATASOURCE_PORT} + mail: + host: ${DEV_MAIL_HOST} + port: 587 + username: ${DEV_MAIL_USERNAME} + password: ${DEV_MAIL_PASSWORD} + from: ${DEV_MAIL_SENDER} + properties: + mail: + smtp: + auth: true + starttls: + enable: true cors: allowed-origins: https://dev.areyouhere.today, https://dev.www.areyouhere.today - cookie: encode: ${SECRET_KEY} diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index 082cdc2..60b6d3d 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -23,10 +23,21 @@ spring: redis: host: localhost port: 6379 - + mail: + host: null + port: 1 + username: null + password: null + from: null + properties: + mail: + smtp: + auth: false + starttls: + enable: false logging: level: - root: info + root: debug cors: allowed-origins: http://localhost:5173 diff --git a/src/main/resources/application-release.yaml b/src/main/resources/application-release.yaml index 88705df..46e7440 100644 --- a/src/main/resources/application-release.yaml +++ b/src/main/resources/application-release.yaml @@ -7,18 +7,26 @@ spring: username: ${MYSQL_DATASOURCE_USERNAME} password: ${MYSQL_DATASOURCE_PASSWORD} jpa: - show-sql: true hibernate: ddl-auto: update - properties: - hibernate: - format_sql: true database: mysql open-in-view: false data: redis: host: ${REDIS_DATASOURCE_HOST} port: ${REDIS_DATASOURCE_PORT} + mail: + host: ${RELEASE_MAIL_HOST} + port: 587 + username: ${RELEASE_MAIL_USERNAME} + password: ${RELEASE_MAIL_PASSWORD} + from: ${RELEASE_MAIL_SENDER} + properties: + mail: + smtp: + auth: true + starttls: + enable: false cors: From 14187c5bd67d6aed3e6b25583ce813d85bdccdd1 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Fri, 28 Jun 2024 17:53:33 +0900 Subject: [PATCH 14/19] =?UTF-8?q?Feat/Log-Error=20=EC=8A=AC=EB=9E=99?= =?UTF-8?q?=EC=97=90=20=EC=97=90=EB=9F=AC=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99=20(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/develop.yaml | 1 + .github/workflows/release.yaml | 1 + build.gradle | 2 +- .../areyouhere/AreYouHereApplication.java | 8 ++ .../common/annotation/SlackNotification.java | 11 +++ .../areyouhere/common/config/SlackAspect.java | 83 +++++++++++++++++++ .../common/error/ErrorResponse.java | 18 ++++ .../common/error/GlobalExceptionHandler.java | 42 ++++++++++ .../areyouhere/common/utils/RequestInfo.java | 23 +++++ src/main/resources/application-dev.yaml | 4 +- src/main/resources/application-prod.yaml | 3 + 11 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/waruru/areyouhere/common/annotation/SlackNotification.java create mode 100644 src/main/java/com/waruru/areyouhere/common/config/SlackAspect.java create mode 100644 src/main/java/com/waruru/areyouhere/common/error/ErrorResponse.java create mode 100644 src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java create mode 100644 src/main/java/com/waruru/areyouhere/common/utils/RequestInfo.java diff --git a/.github/workflows/develop.yaml b/.github/workflows/develop.yaml index ed02940..ddeac11 100644 --- a/.github/workflows/develop.yaml +++ b/.github/workflows/develop.yaml @@ -43,6 +43,7 @@ jobs: spring.mail.username: ${{ secrets.DEV_MAIL_USERNAME }} spring.mail.password: ${{ secrets.DEV_MAIL_PASSWORD }} spring.mail.from: ${{ secrets.DEV_MAIL_SENDER }} + slack.webhook.url: ${{ secrets.SLACK_WEBHOOK_URL }} cookie.encode: ${{ secrets.SECRET_KEY }} - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7527f2d..91b55aa 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -40,6 +40,7 @@ jobs: spring.mail.username: ${{ secrets.RELEASE_MAIL_USERNAME }} spring.mail.password: ${{ secrets.RELEASE_MAIL_PASSWORD }} spring.mail.from: ${{ secrets.RELEASE_MAIL_SENDER }} + slack.webhook.url: ${{ secrets.SLACK_WEBHOOK_URL }} cookie.encode: ${{ secrets.SECRET_KEY }} - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/build.gradle b/build.gradle index 2c7196b..c6267e2 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation "org.springframework.boot:spring-boot-starter-security" implementation 'org.springframework.boot:spring-boot-starter-mail' - + implementation 'net.gpedro.integrations.slack:slack-webhook:1.4.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' runtimeOnly 'com.h2database:h2' diff --git a/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java b/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java index 225f044..260808d 100644 --- a/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java +++ b/src/main/java/com/waruru/areyouhere/AreYouHereApplication.java @@ -1,12 +1,18 @@ package com.waruru.areyouhere; +import com.waruru.areyouhere.common.annotation.SlackNotification; import jakarta.annotation.PostConstruct; +import jakarta.servlet.http.HttpServletRequest; import java.util.TimeZone; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.http.HttpStatus; import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.web.ErrorResponse; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; @EnableJpaAuditing @EnableAsync @@ -22,4 +28,6 @@ void started(){ TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")); } + + } diff --git a/src/main/java/com/waruru/areyouhere/common/annotation/SlackNotification.java b/src/main/java/com/waruru/areyouhere/common/annotation/SlackNotification.java new file mode 100644 index 0000000..d0c7241 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/common/annotation/SlackNotification.java @@ -0,0 +1,11 @@ +package com.waruru.areyouhere.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface SlackNotification { +} diff --git a/src/main/java/com/waruru/areyouhere/common/config/SlackAspect.java b/src/main/java/com/waruru/areyouhere/common/config/SlackAspect.java new file mode 100644 index 0000000..7777291 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/common/config/SlackAspect.java @@ -0,0 +1,83 @@ +package com.waruru.areyouhere.common.config; + +import static java.util.Collections.singletonList; + +import com.waruru.areyouhere.common.utils.RequestInfo; +import java.util.List; +import java.util.Arrays; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import jakarta.servlet.http.HttpServletRequest; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; + +import net.gpedro.integrations.slack.SlackApi; +import net.gpedro.integrations.slack.SlackAttachment; +import net.gpedro.integrations.slack.SlackField; +import net.gpedro.integrations.slack.SlackMessage; + + +@Aspect +@Component +@Profile(value = {"develop", "prod"}) +public class SlackAspect { + private final SlackApi slackApi; + private final ThreadPoolTaskExecutor threadPoolTaskExecutor; + private final Environment env; + + public SlackAspect(@Value("${slack.webhook.url}") String webhook, + ThreadPoolTaskExecutor threadPoolTaskExecutor, Environment env) { + this.slackApi = new SlackApi(webhook); + this.threadPoolTaskExecutor = threadPoolTaskExecutor; + this.env = env; + } + + @Around("@annotation(com.waruru.areyouhere.common.annotation.SlackNotification) && args(request, e)") + public void slackNotificate(ProceedingJoinPoint proceedingJoinPoint, HttpServletRequest request, + Exception e) throws Throwable { + + proceedingJoinPoint.proceed(); + + RequestInfo requestInfo = new RequestInfo(request); + + threadPoolTaskExecutor.execute(() -> { + sendSlackMessage(requestInfo, e); + }); + } + + private void sendSlackMessage(RequestInfo request, Exception e) { + SlackAttachment slackAttachment = new SlackAttachment(); + slackAttachment.setFallback("Error"); + slackAttachment.setColor("danger"); + + slackAttachment.setFields( + List.of( + new SlackField().setTitle("Exception class").setValue(e.getClass().getCanonicalName()), + new SlackField().setTitle("예외 메시지").setValue(e.getMessage()), + new SlackField().setTitle("Request URI").setValue(request.requestURL()), + new SlackField().setTitle("Request Method").setValue(request.method()), + new SlackField().setTitle("요청 시간") + .setValue(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))), + new SlackField().setTitle("Request IP").setValue(request.remoteAddress()), + new SlackField().setTitle("Profile 정보").setValue(Arrays.toString(env.getActiveProfiles())) + ) + ); + + SlackMessage slackMessage = new SlackMessage(); + slackMessage.setAttachments(singletonList(slackAttachment)); + slackMessage.setIcon(":ghost:"); + slackMessage.setText("Error occurred in the application"); + slackMessage.setUsername("SHEOMM"); + + slackApi.call(slackMessage); + } + +} diff --git a/src/main/java/com/waruru/areyouhere/common/error/ErrorResponse.java b/src/main/java/com/waruru/areyouhere/common/error/ErrorResponse.java new file mode 100644 index 0000000..913fe66 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/common/error/ErrorResponse.java @@ -0,0 +1,18 @@ +package com.waruru.areyouhere.common.error; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +public record ErrorResponse( + String code, + String message +) { + + public static ErrorResponse of(String code, String message) { + return new ErrorResponse(code, message); + } + +} diff --git a/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java b/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java new file mode 100644 index 0000000..61a8f35 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java @@ -0,0 +1,42 @@ +package com.waruru.areyouhere.common.error; + +import com.waruru.areyouhere.common.annotation.SlackNotification; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import net.gpedro.integrations.slack.SlackApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + private final SlackApi slackApi; + + public GlobalExceptionHandler(@Value("${spring.slack.webhook}") String webhook) { + this.slackApi = new SlackApi(webhook); + } + + @SlackNotification + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(Exception.class) + @Profile(value = {"develop", "prod"}) + public ErrorResponse handleException(HttpServletRequest request, Exception e) { + log.error("Internal Server Error", e); + StringBuilder sb = new StringBuilder(); + sb.append(request.getMethod()); + sb.append(request.getRemoteAddr()); + sb.append(request.getRequestURL()); + sb.append(e.getMessage()); + + return ErrorResponse.of("INTERNAL SERVER ERROR", sb.toString()); + } + + + +} diff --git a/src/main/java/com/waruru/areyouhere/common/utils/RequestInfo.java b/src/main/java/com/waruru/areyouhere/common/utils/RequestInfo.java new file mode 100644 index 0000000..d6f36f7 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/common/utils/RequestInfo.java @@ -0,0 +1,23 @@ +package com.waruru.areyouhere.common.utils; + +import jakarta.servlet.http.HttpServletRequest; + +public record RequestInfo( + String requestURL, + String method, + String remoteAddress +) { + + public RequestInfo(String requestURL, String method, String remoteAddress) { + this.requestURL = requestURL; + this.method = method; + this.remoteAddress = remoteAddress; + } + + public RequestInfo(HttpServletRequest request) { + this(String.valueOf(request.getRequestURL()), + request.getMethod(), + request.getRemoteAddr() + ); + } +} diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 6e41b16..3d683ae 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -31,7 +31,9 @@ spring: auth: true starttls: enable: true - +slack: + webhook: + url: ${SLACK_WEBHOOK_URL} cors: allowed-origins: https://dev.areyouhere.today, https://dev.www.areyouhere.today diff --git a/src/main/resources/application-prod.yaml b/src/main/resources/application-prod.yaml index d877dd5..5d157aa 100644 --- a/src/main/resources/application-prod.yaml +++ b/src/main/resources/application-prod.yaml @@ -11,6 +11,9 @@ spring: host: ${AWS_ELASTICACHE_HOST} database: ${AWS_ELASTICACHE_DATABASE} port: 6379 +slack: + webhook: + url: ${SLACK_WEBHOOK_URL} cookie: encode: TEMP \ No newline at end of file From 38c78aa9319d0bfa87ff9cde2bacc6bc7b142c29 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Sat, 29 Jun 2024 00:33:04 +0900 Subject: [PATCH 15/19] =?UTF-8?q?Fix/Error-Log=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=EB=A7=8C=20=EC=A0=84=EC=86=A1=20(#59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attendance/advice/AttendanceExceptionAdvice.java | 4 ++++ .../attendee/advice/AttendeeExceptionAdvice.java | 3 +++ .../areyouhere/common/error/GlobalExceptionHandler.java | 8 ++------ .../java/com/waruru/areyouhere/common/utils/Ordered.java | 7 +++++++ .../areyouhere/course/advice/CourseExceptionAdvice.java | 3 +++ .../areyouhere/manager/advice/ManagerExceptionAdvice.java | 3 +++ .../areyouhere/session/advice/SessionExceptionAdvice.java | 3 +++ src/main/resources/application-release.yaml | 4 +++- 8 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/waruru/areyouhere/common/utils/Ordered.java diff --git a/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java index 9e96db2..7253ac3 100644 --- a/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/attendance/advice/AttendanceExceptionAdvice.java @@ -8,16 +8,20 @@ import com.waruru.areyouhere.attendance.exception.AlreadyAttendException; import com.waruru.areyouhere.attendance.exception.DuplicateAuthCodeAttendException; import com.waruru.areyouhere.attendance.exception.AuthCodeNotFoundException; +import com.waruru.areyouhere.common.utils.Ordered; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice("com.waruru.areyouhere.attendance") +@Order(Ordered.SECOND_VALUE) public class AttendanceExceptionAdvice { + @ExceptionHandler(SessionIdNotFoundException.class) public ResponseEntity sessionIdNotFoundHandler() { return RESPONSE_NOT_FOUND; diff --git a/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java index 2aae986..5074088 100644 --- a/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/attendee/advice/AttendeeExceptionAdvice.java @@ -9,14 +9,17 @@ import com.waruru.areyouhere.attendee.exception.ClassAttendeesEmptyException; import com.waruru.areyouhere.attendee.exception.SessionAttendeesEmptyException; import com.waruru.areyouhere.attendee.exception.AttendeesNotUniqueException; +import com.waruru.areyouhere.common.utils.Ordered; import com.waruru.areyouhere.course.exception.CourseNotFoundException; import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice("com.waruru.areyouhere.attendee") +@Order(Ordered.SECOND_VALUE) public class AttendeeExceptionAdvice { @ExceptionHandler(ActivatedSessionExistsException.class) diff --git a/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java b/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java index 61a8f35..8ef636e 100644 --- a/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java +++ b/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java @@ -6,6 +6,8 @@ import net.gpedro.integrations.slack.SlackApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -16,12 +18,6 @@ @RestControllerAdvice public class GlobalExceptionHandler { - private final SlackApi slackApi; - - public GlobalExceptionHandler(@Value("${spring.slack.webhook}") String webhook) { - this.slackApi = new SlackApi(webhook); - } - @SlackNotification @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) diff --git a/src/main/java/com/waruru/areyouhere/common/utils/Ordered.java b/src/main/java/com/waruru/areyouhere/common/utils/Ordered.java new file mode 100644 index 0000000..c44c620 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/common/utils/Ordered.java @@ -0,0 +1,7 @@ +package com.waruru.areyouhere.common.utils; + +public interface Ordered extends org.springframework.core.Ordered { + int SECOND_VALUE = 2; + + int THIRD_VALUE = 3; +} diff --git a/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java index f78edff..a3af266 100644 --- a/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/course/advice/CourseExceptionAdvice.java @@ -3,10 +3,12 @@ import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_BAD_REQUEST; import com.waruru.areyouhere.attendee.exception.AttendeesNotUniqueException; +import com.waruru.areyouhere.common.utils.Ordered; import com.waruru.areyouhere.course.exception.CourseNotFoundException; import com.waruru.areyouhere.manager.exception.ManagerNotFoundException; import com.waruru.areyouhere.course.exception.UnauthorizedManagerException; import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -15,6 +17,7 @@ @RestControllerAdvice("com.waruru.areyouhere.course") +@Order(Ordered.SECOND_VALUE) public class CourseExceptionAdvice { @ExceptionHandler(ManagerNotFoundException.class) public ResponseEntity handleManagerNotFoundException(ManagerNotFoundException ex, WebRequest request) { diff --git a/src/main/java/com/waruru/areyouhere/manager/advice/ManagerExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/manager/advice/ManagerExceptionAdvice.java index cbe3cb1..c9227f1 100644 --- a/src/main/java/com/waruru/areyouhere/manager/advice/ManagerExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/manager/advice/ManagerExceptionAdvice.java @@ -5,14 +5,17 @@ import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_FORBIDDEN; import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_NOT_FOUND; +import com.waruru.areyouhere.common.utils.Ordered; import com.waruru.areyouhere.manager.exception.DuplicatedEmailException; import com.waruru.areyouhere.manager.exception.UnAuthenticatedException; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice("com.waruru.areyouhere.manager") +@Order(Ordered.SECOND_VALUE) public class ManagerExceptionAdvice { @ExceptionHandler(UnAuthenticatedException.class) diff --git a/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java index 2781935..36d60bc 100644 --- a/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java +++ b/src/main/java/com/waruru/areyouhere/session/advice/SessionExceptionAdvice.java @@ -6,11 +6,13 @@ import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_NO_CONTENT; import com.waruru.areyouhere.attendee.exception.AttendeeNotFoundException; +import com.waruru.areyouhere.common.utils.Ordered; import com.waruru.areyouhere.course.exception.CourseNotFoundException; import com.waruru.areyouhere.session.exception.ActivatedSessionExistsException; import com.waruru.areyouhere.session.exception.CurrentSessionDeactivatedException; import com.waruru.areyouhere.session.exception.CurrentSessionNotFoundException; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice("com.waruru.areyouhere.session") +@Order(Ordered.SECOND_VALUE) public class SessionExceptionAdvice { @ExceptionHandler(CurrentSessionNotFoundException.class) diff --git a/src/main/resources/application-release.yaml b/src/main/resources/application-release.yaml index 46e7440..74f4010 100644 --- a/src/main/resources/application-release.yaml +++ b/src/main/resources/application-release.yaml @@ -27,7 +27,9 @@ spring: auth: true starttls: enable: false - +slack: + webhook: + url: ${SLACK_WEBHOOK_URL} cors: allowed-origins: https://areyouhere.today, https://www.areyouhere.today From d01c79ef36eab6df80e5502f140c5ba89956decc Mon Sep 17 00:00:00 2001 From: SHEOM Date: Mon, 8 Jul 2024 21:59:03 +0900 Subject: [PATCH 16/19] =?UTF-8?q?Hotfix/signup:=20=EC=9D=B4=EB=A9=94?= =?UTF-8?q?=EC=9D=BC=20=EC=9D=B8=EC=A6=9D=20=EB=B9=84=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94=20(#61)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../areyouhere/manager/service/SessionManagerService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java index e06c237..ee29114 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java @@ -57,9 +57,9 @@ public void logout() { public void signUp(String email, String password, String nickname) { boolean isEmailDuplicated = isDuplicatedEmail(email); - if (!verifyCodeRepository.isVerified(email)) { - throw new UnAuthenticatedException("이메일 인증을 완료해주세요."); - } +// if (!verifyCodeRepository.isVerified(email)) { +// throw new UnAuthenticatedException("이메일 인증을 완료해주세요."); +// } if (isEmailDuplicated) { throw new DuplicatedEmailException("중복된 이메일입니다."); @@ -72,7 +72,7 @@ public void signUp(String email, String password, String nickname) { .build() ); - verifyCodeRepository.deleteByEmail(email); +// verifyCodeRepository.deleteByEmail(email); sessionManager.createSession(manager.getId()); } From 26fc26ad91b562b3388c8f2ae3fb82267f215c63 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Wed, 7 Aug 2024 18:56:17 +0900 Subject: [PATCH 17/19] =?UTF-8?q?fix:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=9B=90=EB=B3=B5=20(#63)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../areyouhere/manager/service/SessionManagerService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java index bb89310..68926f3 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java @@ -58,9 +58,9 @@ public void signUp(String email, String password, String nickname) { boolean isEmailDuplicated = isDuplicatedEmail(email); -// if (!verifyCodeRepository.isVerified(email)) { -// throw new UnAuthenticatedException("이메일 인증을 완료해주세요."); -// } + if (!verifyCodeRepository.isVerified(email)) { + throw new UnAuthenticatedException("이메일 인증을 완료해주세요."); + } if (isEmailDuplicated) { @@ -75,7 +75,7 @@ public void signUp(String email, String password, String nickname) { ); -// verifyCodeRepository.deleteByEmail(email); + verifyCodeRepository.deleteByEmail(email); sessionManager.createSession(manager.getId()); } From 974e3642e9ed7401cf428d377291afd64910889e Mon Sep 17 00:00:00 2001 From: SHEOM Date: Thu, 8 Aug 2024 18:00:42 +0900 Subject: [PATCH 18/19] =?UTF-8?q?Feat/email:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EC=84=9C=EB=B9=84=EC=8A=A4=20OCI=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EC=88=98=EC=A0=95=20(#67)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../areyouhere/common/config/EmailConfig.java | 44 ----------- .../utils/HttpStatusResponseEntity.java | 1 + .../email/advice/EmailExceptionAdvice.java | 29 ++++++++ .../email/domain/MessageHolder.java | 2 +- .../email/exception/EmailSendException.java | 23 ++++++ .../email/service/JavaEmailServiceImpl.java | 73 ++++++++++++++++--- .../manager/controller/ManagerController.java | 4 +- 7 files changed, 119 insertions(+), 57 deletions(-) delete mode 100644 src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java create mode 100644 src/main/java/com/waruru/areyouhere/email/advice/EmailExceptionAdvice.java create mode 100644 src/main/java/com/waruru/areyouhere/email/exception/EmailSendException.java diff --git a/src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java b/src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java deleted file mode 100644 index ecd4708..0000000 --- a/src/main/java/com/waruru/areyouhere/common/config/EmailConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.waruru.areyouhere.common.config; - -import java.util.Properties; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.JavaMailSenderImpl; - - -@Configuration -@ConfigurationProperties(prefix = "spring.mail") -public class EmailConfig { - private String username; - private String password; - private String host; - private int port; - - @Profile({"develop", "release"}) - @Bean - public JavaMailSender getJavaMailSender() { - JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); - mailSender.setHost(host); - mailSender.setUsername(username); - mailSender.setPassword(password); - mailSender.setPort(port); - - Properties javaMailProperties = new Properties(); - javaMailProperties.put("mail.smtp.auth", "true"); - javaMailProperties.put("mail.smtp.starttls.enable", "true"); - javaMailProperties.put("mail.smtp.starttls.required", "true"); - - mailSender.setJavaMailProperties(javaMailProperties); - - return mailSender; - } - - @Profile("local") - @Bean - public JavaMailSender getLocalJavaMailSender() { - return new JavaMailSenderImpl(); - } -} diff --git a/src/main/java/com/waruru/areyouhere/common/utils/HttpStatusResponseEntity.java b/src/main/java/com/waruru/areyouhere/common/utils/HttpStatusResponseEntity.java index e636f9e..9c4af6e 100644 --- a/src/main/java/com/waruru/areyouhere/common/utils/HttpStatusResponseEntity.java +++ b/src/main/java/com/waruru/areyouhere/common/utils/HttpStatusResponseEntity.java @@ -13,4 +13,5 @@ public class HttpStatusResponseEntity { public static final ResponseEntity RESPONSE_UNAUTHORIZED = ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); public static final ResponseEntity RESPONSE_FORBIDDEN = ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + public static final ResponseEntity RESPONSE_INTERNAL_ERROR = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } diff --git a/src/main/java/com/waruru/areyouhere/email/advice/EmailExceptionAdvice.java b/src/main/java/com/waruru/areyouhere/email/advice/EmailExceptionAdvice.java new file mode 100644 index 0000000..7c111c6 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/email/advice/EmailExceptionAdvice.java @@ -0,0 +1,29 @@ +package com.waruru.areyouhere.email.advice; + + +import com.waruru.areyouhere.common.annotation.SlackNotification; +import com.waruru.areyouhere.common.error.ErrorResponse; +import com.waruru.areyouhere.email.exception.EmailSendException; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +// 이메일 전송이 안되는 것은 이메일 서버에 이상이 있으므로 slack에서 처리될 수 있도록 한다. +@RestControllerAdvice("com.waruru.areyouhere.email") +@Slf4j +public class EmailExceptionAdvice { + + @ExceptionHandler(EmailSendException.class) + @SlackNotification + public ErrorResponse emailSendException(HttpServletRequest request, Exception e){ + log.error("Internal Server Error", e); + StringBuilder sb = new StringBuilder(); + sb.append(request.getMethod()); + sb.append(request.getRemoteAddr()); + sb.append(request.getRequestURL()); + sb.append(e.getMessage()); + + return ErrorResponse.of("INTERNAL SERVER ERROR", sb.toString()); + } +} diff --git a/src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java b/src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java index 90b1d18..65dc85c 100644 --- a/src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java +++ b/src/main/java/com/waruru/areyouhere/email/domain/MessageHolder.java @@ -10,6 +10,6 @@ public class MessageHolder { public MessageHolder(String title, MessageTemplate messageTemplate, Object... values){ this.title = title; - this.contents = String.format(messageTemplate.getTemplate(), (Object) values); + this.contents = String.format(messageTemplate.getTemplate(), values); } } diff --git a/src/main/java/com/waruru/areyouhere/email/exception/EmailSendException.java b/src/main/java/com/waruru/areyouhere/email/exception/EmailSendException.java new file mode 100644 index 0000000..d076017 --- /dev/null +++ b/src/main/java/com/waruru/areyouhere/email/exception/EmailSendException.java @@ -0,0 +1,23 @@ +package com.waruru.areyouhere.email.exception; + +public class EmailSendException extends RuntimeException{ + + public EmailSendException() { + } + + public EmailSendException(String message) { + super(message); + } + + public EmailSendException(String message, Throwable cause) { + super(message, cause); + } + + public EmailSendException(Throwable cause) { + super(cause); + } + + public EmailSendException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java b/src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java index 3d28efa..4619ab0 100644 --- a/src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/email/service/JavaEmailServiceImpl.java @@ -2,21 +2,36 @@ import com.waruru.areyouhere.email.domain.MessageHolder; import com.waruru.areyouhere.email.domain.MessageTemplate; +import com.waruru.areyouhere.email.exception.EmailSendException; +import jakarta.mail.Message.RecipientType; +import jakarta.mail.MessagingException; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; +import java.io.UnsupportedEncodingException; +import java.util.Properties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; -import org.springframework.mail.SimpleMailMessage; -import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Service; @RequiredArgsConstructor @Service @Slf4j public class JavaEmailServiceImpl implements EmailService { - private final JavaMailSender emailSender; @Value("${spring.mail.from}") private String from; + @Value("${spring.mail.username}") + private String username; + @Value("${spring.mail.password}") + private String password; + @Value("${spring.mail.host}") + private String host; + @Value("${spring.mail.port}") + private int port; + public void sendVerifyEmail(String to, String title, String verificationLink, MessageTemplate messageTemplate) { @@ -24,17 +39,55 @@ public void sendVerifyEmail(String to, String title, String verificationLink, Me sendSimpleMessage(to, messageHolder.getTitle(), messageHolder.getContents()); } - private void sendSimpleMessage(String to, String title, String content) { + private void sendSimpleMessage(String to, String title, String content) { if (from == null || from.isEmpty()) { log.info("Email text Test: " + content); return; } - SimpleMailMessage message = new SimpleMailMessage(); - message.setFrom(from); - message.setTo(to); - message.setSubject(title); - message.setText(content); - emailSender.send(message); + + Session session = getSession(); + try { + MimeMessage msg = setMessage(to, from, content, session); + doSend(session, msg); + + } catch (MessagingException | UnsupportedEncodingException e) { + throw new EmailSendException(); + } + + + } + + private void doSend(Session session, MimeMessage msg) throws MessagingException { + Transport transport = session.getTransport(); + transport.connect(host, username, password); + transport.sendMessage(msg, msg.getAllRecipients()); + transport.close(); + } + + private MimeMessage setMessage(String to, String title, String content, Session session) + throws MessagingException, UnsupportedEncodingException { + MimeMessage msg = new MimeMessage(session); + msg.setFrom(new InternetAddress(from, from)); + InternetAddress internetAddress = new InternetAddress(to); + internetAddress.validate(); + msg.setRecipient(RecipientType.TO, internetAddress); + msg.setSubject(title); + msg.setContent(content, "text/html"); + msg.setHeader("X-SES-CONFIGURATION-SET", "ConfigSet"); + return msg; + } + + private Session getSession(){ + Properties emailProps = System.getProperties(); + emailProps.put("mail.transport.protocol", "smtp"); + emailProps.put("mail.smtp.port", port); + emailProps.put("mail.smtp.starttls.required", "true"); + emailProps.put("mail.smtp.auth.login.disable", "true"); + emailProps.put("mail.smtp.starttls.enable", "true"); + emailProps.put("mail.smtp.auth", "true"); + + return Session.getDefaultInstance(emailProps); + } } diff --git a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java index 9fd61b3..c0dfafe 100644 --- a/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java +++ b/src/main/java/com/waruru/areyouhere/manager/controller/ManagerController.java @@ -101,13 +101,13 @@ public ResponseEntity delete(@Login Manager manager) { @GetMapping("/email") public ResponseEntity sendSignUpEmail(@RequestParam String email) { managerService.sendEmailForSignUp(email); - return RESPONSE_BAD_REQUEST; + return RESPONSE_OK; } @GetMapping("/password") public ResponseEntity sendPasswordEmail(@RequestParam String email) { managerService.sendEmailForPasswordReset(email); - return RESPONSE_BAD_REQUEST; + return RESPONSE_OK; } @PostMapping("/verification") From 62e2f51305f728c2780948f029c3c4e46cd43922 Mon Sep 17 00:00:00 2001 From: SHEOM Date: Sun, 11 Aug 2024 18:17:29 +0900 Subject: [PATCH 19/19] =?UTF-8?q?Fix/Api-Error:=20Session=20Date=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20404=20=EC=98=A4=EB=A5=98=20Global=20Handl?= =?UTF-8?q?ing,=20API=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95=20(#68)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../active/service/ActiveSessionServiceImpl.java | 1 + .../auth/interceptor/LoginInterceptor.java | 2 +- .../areyouhere/auth/session/SessionManager.java | 7 ------- .../common/error/GlobalExceptionHandler.java | 13 +++++++++---- .../domain/repository/CourseRepository.java | 6 +++++- .../course/service/CourseServiceImpl.java | 16 ++++++++++------ .../areyouhere/email/domain/MessageTemplate.java | 4 ++-- .../manager/service/SessionManagerService.java | 14 ++++++++++++-- .../service/command/SessionCommandService.java | 3 +++ .../command/SessionCommandServiceImpl.java | 7 +++++++ 10 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java index 5ab1cd7..a3a7ae3 100644 --- a/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/active/service/ActiveSessionServiceImpl.java @@ -31,6 +31,7 @@ public String activate(Long sessionId, Long courseId) { Course course = courseService.get(courseId); Session session = sessionQueryService.get(sessionId); LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); + sessionCommandService.setAuthCodeDate(session, currentTime); return activeAttendanceService.activate(course, session, currentTime); } diff --git a/src/main/java/com/waruru/areyouhere/auth/interceptor/LoginInterceptor.java b/src/main/java/com/waruru/areyouhere/auth/interceptor/LoginInterceptor.java index 20634e8..61a2b26 100644 --- a/src/main/java/com/waruru/areyouhere/auth/interceptor/LoginInterceptor.java +++ b/src/main/java/com/waruru/areyouhere/auth/interceptor/LoginInterceptor.java @@ -33,7 +33,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons // TODO: 인증과 인가는 별개이다. 인가 중에서도 각 user가 어디 record에 접근권한을 가질 지 제어하는 공통된 로직을 고민해 봐야 한다. // TODO } catch (UnAuthenticatedException e) { - request.getRequestDispatcher("/api/manager/unauthorized").forward(request, response); + request.getRequestDispatcher("/api/auth/unauthorized").forward(request, response); return false; } } diff --git a/src/main/java/com/waruru/areyouhere/auth/session/SessionManager.java b/src/main/java/com/waruru/areyouhere/auth/session/SessionManager.java index 51332ec..630bd9e 100644 --- a/src/main/java/com/waruru/areyouhere/auth/session/SessionManager.java +++ b/src/main/java/com/waruru/areyouhere/auth/session/SessionManager.java @@ -17,17 +17,10 @@ public class SessionManager { private final HttpSession httpSession; - private final CourseRepository courseRepository; private static final String LOG_ID = "logId"; public void createSession(Long managerId){ - List courses = courseRepository.findAllByManagerId(managerId); - - List courseIds = courses == null || courses.isEmpty() ? - Collections.emptyList() - : courses.stream().map(course -> course.getManager().getId()).toList(); - LoginUser loginUser = new LoginUser(managerId); httpSession.setAttribute(LOG_ID, loginUser); } diff --git a/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java b/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java index 8ef636e..687adbc 100644 --- a/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java +++ b/src/main/java/com/waruru/areyouhere/common/error/GlobalExceptionHandler.java @@ -1,23 +1,28 @@ package com.waruru.areyouhere.common.error; +import static com.waruru.areyouhere.common.utils.HttpStatusResponseEntity.RESPONSE_NOT_FOUND; + import com.waruru.areyouhere.common.annotation.SlackNotification; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; -import net.gpedro.integrations.slack.SlackApi; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { + + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity handle404Exception(HttpServletRequest request, Exception e){ + return RESPONSE_NOT_FOUND; + } + @SlackNotification @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) diff --git a/src/main/java/com/waruru/areyouhere/course/domain/repository/CourseRepository.java b/src/main/java/com/waruru/areyouhere/course/domain/repository/CourseRepository.java index ceda2ee..3896c36 100644 --- a/src/main/java/com/waruru/areyouhere/course/domain/repository/CourseRepository.java +++ b/src/main/java/com/waruru/areyouhere/course/domain/repository/CourseRepository.java @@ -4,8 +4,12 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface CourseRepository extends JpaRepository { - List findAllByManagerId(Long managerId); + + @Query("SELECT c FROM course c WHERE c.manager.id = :managerId") + List findAllByManagerId(@Param("managerId")Long managerId); } diff --git a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java index fd92903..8ade8c1 100644 --- a/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/course/service/CourseServiceImpl.java @@ -11,6 +11,8 @@ import com.waruru.areyouhere.course.domain.repository.CourseRepository; import com.waruru.areyouhere.attendee.exception.AttendeesNotUniqueException; import com.waruru.areyouhere.course.dto.CourseData; +import com.waruru.areyouhere.course.exception.CourseNotFoundException; +import com.waruru.areyouhere.course.exception.UnauthorizedManagerException; import com.waruru.areyouhere.manager.domain.entity.Manager; import com.waruru.areyouhere.manager.domain.repository.ManagerRepository; import com.waruru.areyouhere.session.domain.entity.Session; @@ -45,7 +47,7 @@ public class CourseServiceImpl implements CourseService { public void create(Long managerId, String name, String description, List attendees, boolean onlyListNameAllowed) { Manager manager = managerRepository.findManagerById(managerId) - .orElseThrow(() -> new IllegalArgumentException("Manager not found")); + .orElseThrow(() -> new UnauthorizedManagerException("Manager not found")); Course course = Course.builder() .manager(manager) @@ -97,10 +99,10 @@ public List getAll(Long managerId) { @Override public void update(Long managerId, Long courseId, String name, String description, boolean onlyListNameAllowed) { Course course = courseRepository.findById(courseId). - orElseThrow(() -> new IllegalArgumentException("Course not found")); + orElseThrow(() -> new CourseNotFoundException("Course not found")); if (!course.getManager().getId().equals(managerId)) { - throw new IllegalArgumentException("Manager not authorized"); + throw new UnauthorizedManagerException("Manager not authorized"); } course.update(name, description, onlyListNameAllowed); @@ -115,10 +117,10 @@ public void delete(Long managerId, Long courseId) { } Course course = courseRepository.findById(courseId). - orElseThrow(() -> new IllegalArgumentException("Course not found")); + orElseThrow(() -> new CourseNotFoundException("Course not found")); if (!course.getManager().getId().equals(managerId)) { - throw new IllegalArgumentException("Manager not authorized"); + throw new UnauthorizedManagerException("Manager not authorized"); } List sessions = sessionRepository.findAllByCourseId(courseId); attendanceRepository.deleteAllBySessionIds(sessions.stream().map(Session::getId).toList()); @@ -127,11 +129,13 @@ public void delete(Long managerId, Long courseId) { courseRepository.delete(course); } + + @Override @Transactional(readOnly = true) public Course get(Long courseId) { return courseRepository.findById(courseId). - orElseThrow(() -> new IllegalArgumentException("Course not found")); + orElseThrow(() -> new CourseNotFoundException("Course not found")); } private boolean isAttendeesUnique(List attendees) { diff --git a/src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java b/src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java index 1668271..f02fc54 100644 --- a/src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java +++ b/src/main/java/com/waruru/areyouhere/email/domain/MessageTemplate.java @@ -1,8 +1,8 @@ package com.waruru.areyouhere.email.domain; public enum MessageTemplate { - PASSWORD_RESET("You can reset password by this link: %s"), - SIGN_UP("You can verify your email by this link: %s"); + PASSWORD_RESET("You can reset password by this code: %s"), + SIGN_UP("You can verify your email by this code: %s"); private final String template; diff --git a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java index 68926f3..6f762f5 100644 --- a/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java +++ b/src/main/java/com/waruru/areyouhere/manager/service/SessionManagerService.java @@ -2,6 +2,7 @@ import com.waruru.areyouhere.auth.entity.LoginUser; import com.waruru.areyouhere.auth.session.SessionManager; +import com.waruru.areyouhere.course.domain.entity.Course; import com.waruru.areyouhere.email.domain.MessageTemplate; import com.waruru.areyouhere.email.service.EmailService; import com.waruru.areyouhere.course.domain.repository.CourseRepository; @@ -11,14 +12,18 @@ import com.waruru.areyouhere.manager.domain.repository.VerifyCodeRepository; import com.waruru.areyouhere.manager.exception.DuplicatedEmailException; import com.waruru.areyouhere.manager.exception.UnAuthenticatedException; +import jakarta.persistence.EntityManager; +import java.util.List; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor +@Slf4j public class SessionManagerService implements ManagerService { // TODO: refactor: 계층 구조 위반 private final CourseService courseService; @@ -27,6 +32,7 @@ public class SessionManagerService implements ManagerService { private final CourseRepository courseRepository; private final ManagerRepository managerRepository; private final VerifyCodeRepository verifyCodeRepository; + private final EntityManager entityManager; private final SessionManager sessionManager; private final PasswordEncoder passwordEncoder; @@ -109,9 +115,13 @@ public void update(Long userId, String name, String password) { @Override @Transactional public void delete(Long userId) { - courseRepository.findAllByManagerId(userId).forEach(course -> courseService.delete(userId, course.getId())); - sessionManager.removeSession(); + courseRepository.findAllByManagerId(userId).forEach(course -> { + courseService.delete(userId, course.getId()); + entityManager.flush(); + }); + managerRepository.deleteById(userId); + sessionManager.removeSession(); } @Override diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java index f84b698..cdc1386 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandService.java @@ -1,5 +1,6 @@ package com.waruru.areyouhere.session.service.command; +import com.waruru.areyouhere.session.domain.entity.Session; import com.waruru.areyouhere.session.service.dto.UpdateSession; import java.time.LocalDateTime; import java.util.List; @@ -13,5 +14,7 @@ public interface SessionCommandService { public void deactivate(Long sessionId); + public void setAuthCodeDate(Session session, LocalDateTime date); + public void updateAll(List sessions); } diff --git a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java index 86edb1b..16448e0 100644 --- a/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java +++ b/src/main/java/com/waruru/areyouhere/session/service/command/SessionCommandServiceImpl.java @@ -13,6 +13,8 @@ import com.waruru.areyouhere.session.exception.CurrentSessionNotFoundException; import com.waruru.areyouhere.session.exception.SessionIdNotFoundException; import com.waruru.areyouhere.session.service.dto.UpdateSession; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -80,6 +82,11 @@ public void deactivate(Long sessionId) { sessionRepository.save(session); } + @Override + public void setAuthCodeDate(Session session, LocalDateTime date){ + session.setAuthCodeCreatedAt(date); + sessionRepository.save(session); + } @Override public void updateAll(List sessions) {