From 455e73271f4b385f808b1a0a868953d95197676a Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Mar 2024 13:23:24 +0900 Subject: [PATCH 1/9] =?UTF-8?q?refactor=20:=20=ED=95=99=EC=83=9D=EC=9D=98?= =?UTF-8?q?=20=EA=B0=95=EC=9D=98=EA=B0=80=20=EC=BA=90=EC=8B=B1=20=EB=90=98?= =?UTF-8?q?=EC=96=B4=EC=9E=88=EB=8A=94=EC=A7=80=20=EC=9E=88=EB=8A=94?= =?UTF-8?q?=EC=A7=80=20=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20isStudentLec?= =?UTF-8?q?tureExist=20=EA=B5=AC=ED=98=84=20(#118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lecture/application/port/AttendeeCacheRepository.java | 2 ++ .../infrastructure/AttendeeCacheRedisRepository.java | 6 ++++++ .../mock/fakerepository/FakeAttendeeCacheRepository.java | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java index 26adda9..b19c2a4 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java @@ -5,6 +5,8 @@ public interface AttendeeCacheRepository { + Boolean isStudentLectureExist(Long studentId, Long lectureId); + Set findAllAttendLectureId(Long studentId); void cache(Long lectureId, StudentIds studentIds); diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java index 410ed85..8889314 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java @@ -21,6 +21,12 @@ public class AttendeeCacheRedisRepository implements AttendeeCacheRepository { private static final String KEY_PREFIX = RedisKeyConstants.LECTURE_STUDENT_KEY_PREFIX; private final RedisTemplate redisTemplate; + @Override + public Boolean isStudentLectureExist(Long studentId, Long lectureId) { + Set openLectureIds = findAllAttendLectureId(studentId); + return openLectureIds.contains(lectureId); + } + @Override public Set findAllAttendLectureId(Long studentId) { String queryKey = KEY_PREFIX + studentId; diff --git a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java index a73e450..1be0a1a 100644 --- a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java +++ b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java @@ -12,6 +12,12 @@ public class FakeAttendeeCacheRepository implements AttendeeCacheRepository { private final Map> data = new HashMap<>(); + @Override + public Boolean isStudentLectureExist(Long studentId, Long lectureId) { + Set openLectureIds = findAllAttendLectureId(studentId); + return openLectureIds.contains(lectureId); + } + @Override public Set findAllAttendLectureId(Long studentId) { return data.getOrDefault( From cee9ccbbf707fd7fa8b12da76960c2cba4b189be Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Mar 2024 13:29:50 +0900 Subject: [PATCH 2/9] =?UTF-8?q?refactor=20:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20AttendeeCacheService=20=EC=A0=9C=EA=B1=B0=20(#118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/StudentAttendanceService.java | 17 +++++++++++++ .../application/AttendeeCacheService.java | 25 ------------------- .../application/OpenLectureService.java | 15 +++++++++++ .../application/AttendeeCacheServiceTest.java | 10 +++++--- .../binaryho/imhere/mock/TestContainer.java | 2 +- 5 files changed, 40 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheService.java diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java index 1cc8a40..2e72473 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java @@ -38,9 +38,11 @@ public class StudentAttendanceService { private final OpenLectureService openLectureService; + private final AttendanceRepository attendanceRepository; private final EnrollmentInfoRepository enrollmentRepository; private final AttendanceHistoryCacheRepository attendanceHistoryCacheRepository; + private final ApplicationEventPublisher eventPublisher; private final SeoulDateTimeHolder seoulDateTimeHolder; @@ -62,6 +64,21 @@ public void takeAttendance(AttendanceRequest attendanceRequest, Long lectureId) attend(attendanceRequest, enrollmentInfo); } + @Transactional + public void takeAttendanceVer2(AttendanceRequest attendanceRequest, Long lectureId) { + Member currentStudent = authenticationHelper.getCurrentMember(); + + EnrollmentInfo enrollmentInfo = enrollmentRepository + .findByMemberIdAndLectureIdAndEnrollmentState(currentStudent.getId(), lectureId, + EnrollmentState.APPROVAL) + .orElseThrow(() -> EnrollmentNotApprovedException.EXCEPTION); + + validateLectureOpen(enrollmentInfo); + validateAttendanceNumber(enrollmentInfo, attendanceRequest.getAttendanceNumber()); + + attend(attendanceRequest, enrollmentInfo); + } + @Transactional(readOnly = true) public StudentRecentAttendanceResponse getStudentRecentAttendance(Long lectureId) { Long studentId = authenticationHelper.getCurrentMember().getId(); diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheService.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheService.java deleted file mode 100644 index d30e72a..0000000 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheService.java +++ /dev/null @@ -1,25 +0,0 @@ -package gdsc.binaryho.imhere.core.lecture.application; - -import gdsc.binaryho.imhere.core.lecture.application.port.AttendeeCacheRepository; -import gdsc.binaryho.imhere.core.lecture.domain.AttendeeCacheEvent; -import lombok.RequiredArgsConstructor; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.event.TransactionPhase; -import org.springframework.transaction.event.TransactionalEventListener; - -@Service -@RequiredArgsConstructor -public class AttendeeCacheService { - - private final AttendeeCacheRepository attendeeCacheRepository; - - @Async - @Transactional(propagation = Propagation.REQUIRES_NEW) - @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) - public void cache(AttendeeCacheEvent event) { - attendeeCacheRepository.cache(event.getLectureId(), event.getStudentIds()); - } -} diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java index 4af925c..4f62484 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java @@ -1,16 +1,24 @@ package gdsc.binaryho.imhere.core.lecture.application; +import gdsc.binaryho.imhere.core.lecture.application.port.AttendeeCacheRepository; import gdsc.binaryho.imhere.core.lecture.application.port.OpenLectureCacheRepository; +import gdsc.binaryho.imhere.core.lecture.domain.AttendeeCacheEvent; import gdsc.binaryho.imhere.core.lecture.domain.OpenLecture; import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; @Service @RequiredArgsConstructor public class OpenLectureService { private final OpenLectureCacheRepository openLectureCacheRepository; + private final AttendeeCacheRepository attendeeCacheRepository; public Optional find(Long lectureId) { return openLectureCacheRepository.find(lectureId); @@ -19,4 +27,11 @@ public Optional find(Long lectureId) { public Integer findAttendanceNumber(Long lectureId) { return openLectureCacheRepository.findAttendanceNumber(lectureId); } + + @Async + @Transactional(propagation = Propagation.REQUIRES_NEW) + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void cache(AttendeeCacheEvent event) { + attendeeCacheRepository.cache(event.getLectureId(), event.getStudentIds()); + } } diff --git a/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java b/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java index ff67075..fa5d5a7 100644 --- a/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java +++ b/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat; import gdsc.binaryho.imhere.core.lecture.application.port.AttendeeCacheRepository; +import gdsc.binaryho.imhere.core.lecture.application.port.OpenLectureCacheRepository; import gdsc.binaryho.imhere.core.lecture.domain.AttendeeCacheEvent; import gdsc.binaryho.imhere.core.lecture.model.StudentIds; import gdsc.binaryho.imhere.mock.TestContainer; @@ -15,20 +16,23 @@ public class AttendeeCacheServiceTest { AttendeeCacheRepository attendeeCacheRepository; - AttendeeCacheService attendeeCacheService; + OpenLectureCacheRepository openLectureCacheRepository; + OpenLectureService openLectureService; @BeforeEach void beforeEach() { TestContainer testContainer = TestContainer.builder().build(); attendeeCacheRepository = testContainer.attendeeCacheRepository; - attendeeCacheService = new AttendeeCacheService(attendeeCacheRepository); + openLectureCacheRepository = testContainer.openLectureCacheRepository; + openLectureService = new OpenLectureService( + openLectureCacheRepository, attendeeCacheRepository); } @Test void Attendee_정보를_저장할_수_있다() { // given StudentIds studentIds = new StudentIds(MOCK_STUDENT.getId()); - attendeeCacheService.cache(new AttendeeCacheEvent(MOCK_LECTURE.getId(), studentIds)); + openLectureService.cache(new AttendeeCacheEvent(MOCK_LECTURE.getId(), studentIds)); // when Set lectureIds = attendeeCacheRepository.findAllAttendLectureId(MOCK_STUDENT.getId()); diff --git a/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java b/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java index 4b9024e..b53e1b5 100644 --- a/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java +++ b/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java @@ -68,7 +68,7 @@ public TestContainer( ); /* OpenLectureService 초기화 */ - openLectureService = new OpenLectureService(openLectureCacheRepository); + openLectureService = new OpenLectureService(openLectureCacheRepository, attendeeCacheRepository); enrollmentService = new EnrollmentService( authenticationHelper, openLectureService, lectureRepository, enrollmentInfoRepository, From 53e2fb5745adf515c3d1759ea696715f596f9cff Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Mar 2024 13:36:02 +0900 Subject: [PATCH 3/9] =?UTF-8?q?refactor=20:=20=EC=BA=90=EC=8B=9C=20reposit?= =?UTF-8?q?ory=20=EC=A0=91=EA=B7=BC=20transactional=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20(#118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/attendance/application/StudentAttendanceService.java | 1 + .../imhere/core/auth/application/EmailVerificationService.java | 1 + .../imhere/core/lecture/application/OpenLectureService.java | 2 ++ 3 files changed, 4 insertions(+) diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java index 2e72473..6cc5960 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java @@ -68,6 +68,7 @@ public void takeAttendance(AttendanceRequest attendanceRequest, Long lectureId) public void takeAttendanceVer2(AttendanceRequest attendanceRequest, Long lectureId) { Member currentStudent = authenticationHelper.getCurrentMember(); + EnrollmentInfo enrollmentInfo = enrollmentRepository .findByMemberIdAndLectureIdAndEnrollmentState(currentStudent.getId(), lectureId, EnrollmentState.APPROVAL) diff --git a/src/main/java/gdsc/binaryho/imhere/core/auth/application/EmailVerificationService.java b/src/main/java/gdsc/binaryho/imhere/core/auth/application/EmailVerificationService.java index f33a8f7..79ddb69 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/auth/application/EmailVerificationService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/auth/application/EmailVerificationService.java @@ -21,6 +21,7 @@ public class EmailVerificationService { private final VerificationCodeRepository verificationCodeRepository; + @Transactional public void sendVerificationCodeByEmail(String recipient) { emailFormValidator.validateEmailForm(recipient); diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java index 4f62484..99cb2fc 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java @@ -20,10 +20,12 @@ public class OpenLectureService { private final OpenLectureCacheRepository openLectureCacheRepository; private final AttendeeCacheRepository attendeeCacheRepository; + @Transactional(readOnly = true) public Optional find(Long lectureId) { return openLectureCacheRepository.find(lectureId); } + @Transactional(readOnly = true) public Integer findAttendanceNumber(Long lectureId) { return openLectureCacheRepository.findAttendanceNumber(lectureId); } From 4459482f8a867cc40f4dc3c31d2df2ecaf782a4d Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Mar 2024 13:54:45 +0900 Subject: [PATCH 4/9] =?UTF-8?q?refactor=20:=20OpenLectureService=EC=97=90?= =?UTF-8?q?=20findAllOpenLectureIdByStudentId=20=EA=B5=AC=ED=98=84=20(#118?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../imhere/core/lecture/application/LectureService.java | 5 ++--- .../core/lecture/application/OpenLectureService.java | 8 +++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java index 0218c88..a1aafde 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java @@ -4,7 +4,6 @@ import gdsc.binaryho.imhere.core.enrollment.EnrollmentState; import gdsc.binaryho.imhere.core.enrollment.infrastructure.EnrollmentInfoRepository; import gdsc.binaryho.imhere.core.lecture.LectureState; -import gdsc.binaryho.imhere.core.lecture.application.port.AttendeeCacheRepository; import gdsc.binaryho.imhere.core.lecture.application.port.OpenLectureCacheRepository; import gdsc.binaryho.imhere.core.lecture.domain.AttendeeCacheEvent; import gdsc.binaryho.imhere.core.lecture.domain.Lecture; @@ -41,8 +40,8 @@ public class LectureService { private final AuthenticationHelper authenticationHelper; private final LectureRepository lectureRepository; private final EnrollmentInfoRepository enrollmentInfoRepository; + private final OpenLectureService openLectureService; private final OpenLectureCacheRepository openLectureCacheRepository; - private final AttendeeCacheRepository attendeeCacheRepository; private final ApplicationEventPublisher eventPublisher; @@ -95,7 +94,7 @@ public LectureResponse getStudentOpenLectures() { } private OpenLectures findCachedOpenLectures(Long studentId) { - Set lectureIds = attendeeCacheRepository.findAllAttendLectureId(studentId); + Set lectureIds = openLectureService.findAllOpenLectureIdByStudentId(studentId); List openLectures = lectureIds.stream() .map(openLectureCacheRepository::find) diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java index 99cb2fc..988212d 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java @@ -5,6 +5,7 @@ import gdsc.binaryho.imhere.core.lecture.domain.AttendeeCacheEvent; import gdsc.binaryho.imhere.core.lecture.domain.OpenLecture; import java.util.Optional; +import java.util.Set; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @@ -30,10 +31,15 @@ public Integer findAttendanceNumber(Long lectureId) { return openLectureCacheRepository.findAttendanceNumber(lectureId); } + @Transactional(readOnly = true) + public Set findAllOpenLectureIdByStudentId(Long studentId) { + return attendeeCacheRepository.findAllAttendLectureId(studentId); + } + @Async @Transactional(propagation = Propagation.REQUIRES_NEW) @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) - public void cache(AttendeeCacheEvent event) { + public void cacheStudent(AttendeeCacheEvent event) { attendeeCacheRepository.cache(event.getLectureId(), event.getStudentIds()); } } From d9d571eeb39b3a1a8b81dff32bab6383b9027b3a Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Mar 2024 13:56:35 +0900 Subject: [PATCH 5/9] =?UTF-8?q?chore=20:=20isStudentLectureExist=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=9D=84=20isStudentOpenLectureExist?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(#118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lecture/application/port/AttendeeCacheRepository.java | 2 +- .../lecture/infrastructure/AttendeeCacheRedisRepository.java | 2 +- .../core/lecture/application/AttendeeCacheServiceTest.java | 2 +- src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java | 5 +++-- .../mock/fakerepository/FakeAttendeeCacheRepository.java | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java index b19c2a4..8461dc8 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/port/AttendeeCacheRepository.java @@ -5,7 +5,7 @@ public interface AttendeeCacheRepository { - Boolean isStudentLectureExist(Long studentId, Long lectureId); + Boolean isStudentOpenLectureExist(Long studentId, Long lectureId); Set findAllAttendLectureId(Long studentId); diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java index 8889314..4a7a1c9 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/infrastructure/AttendeeCacheRedisRepository.java @@ -22,7 +22,7 @@ public class AttendeeCacheRedisRepository implements AttendeeCacheRepository { private final RedisTemplate redisTemplate; @Override - public Boolean isStudentLectureExist(Long studentId, Long lectureId) { + public Boolean isStudentOpenLectureExist(Long studentId, Long lectureId) { Set openLectureIds = findAllAttendLectureId(studentId); return openLectureIds.contains(lectureId); } diff --git a/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java b/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java index fa5d5a7..67e5a0c 100644 --- a/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java +++ b/src/test/java/gdsc/binaryho/imhere/core/lecture/application/AttendeeCacheServiceTest.java @@ -32,7 +32,7 @@ void beforeEach() { void Attendee_정보를_저장할_수_있다() { // given StudentIds studentIds = new StudentIds(MOCK_STUDENT.getId()); - openLectureService.cache(new AttendeeCacheEvent(MOCK_LECTURE.getId(), studentIds)); + openLectureService.cacheStudent(new AttendeeCacheEvent(MOCK_LECTURE.getId(), studentIds)); // when Set lectureIds = attendeeCacheRepository.findAllAttendLectureId(MOCK_STUDENT.getId()); diff --git a/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java b/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java index b53e1b5..8b124bd 100644 --- a/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java +++ b/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java @@ -68,7 +68,8 @@ public TestContainer( ); /* OpenLectureService 초기화 */ - openLectureService = new OpenLectureService(openLectureCacheRepository, attendeeCacheRepository); + openLectureService = new OpenLectureService(openLectureCacheRepository, + attendeeCacheRepository); enrollmentService = new EnrollmentService( authenticationHelper, openLectureService, lectureRepository, enrollmentInfoRepository, @@ -88,7 +89,7 @@ public TestContainer( /* LectureService 초기화 */ lectureService = new LectureService( authenticationHelper, lectureRepository, enrollmentInfoRepository, - openLectureCacheRepository, attendeeCacheRepository, applicationEventPublisher, + openLectureService, openLectureCacheRepository, applicationEventPublisher, seoulDateTimeHolder ); } diff --git a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java index 1be0a1a..227cc56 100644 --- a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java +++ b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendeeCacheRepository.java @@ -13,7 +13,7 @@ public class FakeAttendeeCacheRepository implements AttendeeCacheRepository { private final Map> data = new HashMap<>(); @Override - public Boolean isStudentLectureExist(Long studentId, Long lectureId) { + public Boolean isStudentOpenLectureExist(Long studentId, Long lectureId) { Set openLectureIds = findAllAttendLectureId(studentId); return openLectureIds.contains(lectureId); } From 11aa89623705f491ff6d22980e76ee8fabd05122 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Mar 2024 19:53:05 +0900 Subject: [PATCH 6/9] =?UTF-8?q?feat=20:=20=EC=B6=9C=EC=84=9D=20=EA=B3=BC?= =?UTF-8?q?=EC=A0=95=EC=97=90=EC=84=9C=20=ED=95=99=EC=83=9D=EC=9D=B4=20?= =?UTF-8?q?=EC=88=98=EA=B0=95=EC=8B=A0=EC=B2=AD=EC=97=90=20=EC=8A=B9?= =?UTF-8?q?=EC=9D=B8=20=EB=90=98=EC=97=88=EA=B3=A0,=20=EC=88=98=EC=97=85?= =?UTF-8?q?=EC=9D=B4=20=EC=97=B4=EB=A0=A4=EC=9E=88=EB=8A=94=EC=A7=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=ED=95=A0=20=EB=95=8C,=20Look=20Aside?= =?UTF-8?q?=EB=A1=9C=20=EC=BA=90=EC=8B=9C=20=EB=A8=BC=EC=A0=80=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20(#1?= =?UTF-8?q?18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/StudentAttendanceService.java | 74 +++++++++++-------- .../application/OpenLectureService.java | 5 ++ .../binaryho/imhere/mock/TestContainer.java | 2 +- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java index 6cc5960..4aefc9e 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java @@ -1,8 +1,8 @@ package gdsc.binaryho.imhere.core.attendance.application; -import gdsc.binaryho.imhere.core.attendance.domain.Attendance; import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; +import gdsc.binaryho.imhere.core.attendance.domain.Attendance; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; import gdsc.binaryho.imhere.core.attendance.exception.AttendanceNumberIncorrectException; import gdsc.binaryho.imhere.core.attendance.exception.AttendanceTimeExceededException; @@ -17,7 +17,9 @@ import gdsc.binaryho.imhere.core.lecture.LectureState; import gdsc.binaryho.imhere.core.lecture.application.OpenLectureService; import gdsc.binaryho.imhere.core.lecture.domain.Lecture; +import gdsc.binaryho.imhere.core.lecture.exception.LectureNotFoundException; import gdsc.binaryho.imhere.core.lecture.exception.LectureNotOpenException; +import gdsc.binaryho.imhere.core.lecture.infrastructure.LectureRepository; import gdsc.binaryho.imhere.core.member.Member; import gdsc.binaryho.imhere.security.util.AuthenticationHelper; import gdsc.binaryho.imhere.util.SeoulDateTimeHolder; @@ -39,6 +41,7 @@ public class StudentAttendanceService { private final OpenLectureService openLectureService; + private final LectureRepository lectureRepository; private final AttendanceRepository attendanceRepository; private final EnrollmentInfoRepository enrollmentRepository; private final AttendanceHistoryCacheRepository attendanceHistoryCacheRepository; @@ -53,31 +56,15 @@ public class StudentAttendanceService { @Transactional public void takeAttendance(AttendanceRequest attendanceRequest, Long lectureId) { Member currentStudent = authenticationHelper.getCurrentMember(); - EnrollmentInfo enrollmentInfo = enrollmentRepository - .findByMemberIdAndLectureIdAndEnrollmentState(currentStudent.getId(), lectureId, - EnrollmentState.APPROVAL) - .orElseThrow(() -> EnrollmentNotApprovedException.EXCEPTION); - validateLectureOpen(enrollmentInfo); - validateAttendanceNumber(enrollmentInfo, attendanceRequest.getAttendanceNumber()); - - attend(attendanceRequest, enrollmentInfo); - } - - @Transactional - public void takeAttendanceVer2(AttendanceRequest attendanceRequest, Long lectureId) { - Member currentStudent = authenticationHelper.getCurrentMember(); - - - EnrollmentInfo enrollmentInfo = enrollmentRepository - .findByMemberIdAndLectureIdAndEnrollmentState(currentStudent.getId(), lectureId, - EnrollmentState.APPROVAL) - .orElseThrow(() -> EnrollmentNotApprovedException.EXCEPTION); - - validateLectureOpen(enrollmentInfo); - validateAttendanceNumber(enrollmentInfo, attendanceRequest.getAttendanceNumber()); + if (isOpenLectureCacheExist(currentStudent.getId(), lectureId)) { + Lecture lecture = lectureRepository.findById(lectureId) + .orElseThrow(() -> LectureNotFoundException.EXCEPTION); + attend(attendanceRequest, currentStudent, lecture); + return; + } - attend(attendanceRequest, enrollmentInfo); + attendWithEnrollmentInfo(attendanceRequest, lectureId, currentStudent); } @Transactional(readOnly = true) @@ -107,6 +94,20 @@ public StudentAttendanceResponse getStudentDayAttendance(Long lectureId, Long mi return new StudentAttendanceResponse(attendances); } + private void attendWithEnrollmentInfo(AttendanceRequest attendanceRequest, Long lectureId, + Member currentStudent) { + EnrollmentInfo enrollmentInfo = enrollmentRepository + .findByMemberIdAndLectureIdAndEnrollmentState(currentStudent.getId(), lectureId, + EnrollmentState.APPROVAL) + .orElseThrow(() -> EnrollmentNotApprovedException.EXCEPTION); + validateLectureOpen(enrollmentInfo); + attend(attendanceRequest, enrollmentInfo.getMember(), enrollmentInfo.getLecture()); + } + + private boolean isOpenLectureCacheExist(Long studentId, Long lectureId) { + return openLectureService.isStudentOpenLectureExist(studentId, lectureId); + } + private List getRecentAttendanceTimestamps(Long lectureId, Long studentId) { List attendances = findRecentAttendances(lectureId, studentId); List timestamps = attendances.stream() @@ -140,8 +141,7 @@ private void validateLectureOpen(EnrollmentInfo enrollmentInfo) { } } - private void validateAttendanceNumber(EnrollmentInfo enrollmentInfo, int attendanceNumber) { - long lectureId = enrollmentInfo.getLecture().getId(); + private void validateAttendanceNumber(Long lectureId, int attendanceNumber) { Integer actualAttendanceNumber = openLectureService.findAttendanceNumber(lectureId); validateAttendanceNumberNotTimeOut(actualAttendanceNumber); @@ -160,7 +160,22 @@ private void attend(AttendanceRequest attendanceRequest, EnrollmentInfo enrollme attendanceRepository.save(attendance); publishStudentAttendedEvent(attendance, lecture, student); - logAttendanceHistory(enrollmentInfo, attendance); + logAttendanceHistory(enrollmentInfo.getMember(), attendance); + } + + private void attend(AttendanceRequest attendanceRequest, Member student, Lecture lecture) { + validateAttendanceNumber(lecture.getId(), attendanceRequest.getAttendanceNumber()); + + Attendance attendance = Attendance.createAttendance( + student, lecture, + attendanceRequest.getDistance(), + attendanceRequest.getAccuracy(), + seoulDateTimeHolder.from(attendanceRequest.getMilliseconds()) + ); + + attendanceRepository.save(attendance); + publishStudentAttendedEvent(attendance, lecture, student); + logAttendanceHistory(student, attendance); } private void publishStudentAttendedEvent( @@ -170,12 +185,11 @@ private void publishStudentAttendedEvent( new StudentAttendedEvent(lecture.getId(), student.getId(), timestamp)); } - private void logAttendanceHistory(EnrollmentInfo enrollmentInfo, Attendance attendance) { + private void logAttendanceHistory(Member student, Attendance attendance) { Lecture lecture = attendance.getLecture(); - Member attendMember = enrollmentInfo.getMember(); log.info("[출석 완료] {}({}) , 학생 : {} ({})", lecture::getLectureName, lecture::getId, - attendMember::getUnivId, attendMember::getName); + student::getUnivId, student::getName); } private void validateAttendanceNumberNotTimeOut(Integer attendanceNumber) { diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java index 988212d..022ec1b 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/OpenLectureService.java @@ -36,6 +36,11 @@ public Set findAllOpenLectureIdByStudentId(Long studentId) { return attendeeCacheRepository.findAllAttendLectureId(studentId); } + @Transactional(readOnly = true) + public Boolean isStudentOpenLectureExist(Long studentId, Long lectureId) { + return attendeeCacheRepository.isStudentOpenLectureExist(studentId, lectureId); + } + @Async @Transactional(propagation = Propagation.REQUIRES_NEW) @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) diff --git a/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java b/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java index 8b124bd..fb81d50 100644 --- a/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java +++ b/src/test/java/gdsc/binaryho/imhere/mock/TestContainer.java @@ -82,7 +82,7 @@ public TestContainer( ); studentAttendanceService = new StudentAttendanceService(openLectureService, - attendanceRepository, enrollmentInfoRepository, attendanceHistoryCacheRepository, + lectureRepository, attendanceRepository, enrollmentInfoRepository, attendanceHistoryCacheRepository, applicationEventPublisher, seoulDateTimeHolder, authenticationHelper ); From d375ae82498ae6bf4f2ef072036c485a7f0a3cc0 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sun, 17 Mar 2024 17:47:04 +0900 Subject: [PATCH 7/9] =?UTF-8?q?refactor=20:=20AttendanceHistories=20?= =?UTF-8?q?=EB=9E=98=ED=95=91=20=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?(#118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/StudentAttendanceService.java | 31 ++++++++++--------- .../AttendanceHistoryCacheRepository.java | 4 +-- .../domain/AttendanceHistories.java | 21 +++++++++++++ .../AttendanceRedisCacheRepository.java | 9 +++--- .../FakeAttendanceHistoryCacheRepository.java | 8 +++-- 5 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java index 4aefc9e..cc9d122 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java @@ -3,6 +3,7 @@ import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; import gdsc.binaryho.imhere.core.attendance.domain.Attendance; +import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; import gdsc.binaryho.imhere.core.attendance.exception.AttendanceNumberIncorrectException; import gdsc.binaryho.imhere.core.attendance.exception.AttendanceTimeExceededException; @@ -71,15 +72,15 @@ public void takeAttendance(AttendanceRequest attendanceRequest, Long lectureId) public StudentRecentAttendanceResponse getStudentRecentAttendance(Long lectureId) { Long studentId = authenticationHelper.getCurrentMember().getId(); - List attendanceHistories = attendanceHistoryCacheRepository + AttendanceHistories attendanceHistories = attendanceHistoryCacheRepository .findAllByLectureIdAndStudentId(lectureId, studentId); - if (attendanceHistories.isEmpty()) { - List timestamps = getRecentAttendanceTimestamps(lectureId, studentId); + if (attendanceHistories.isNotEmpty()) { + List timestamps = getTimestamps(attendanceHistories); return new StudentRecentAttendanceResponse(timestamps); } - List timestamps = getTimestamps(attendanceHistories); + List timestamps = getRecentAttendanceTimestamps(lectureId, studentId); return new StudentRecentAttendanceResponse(timestamps); } @@ -108,15 +109,6 @@ private boolean isOpenLectureCacheExist(Long studentId, Long lectureId) { return openLectureService.isStudentOpenLectureExist(studentId, lectureId); } - private List getRecentAttendanceTimestamps(Long lectureId, Long studentId) { - List attendances = findRecentAttendances(lectureId, studentId); - List timestamps = attendances.stream() - .map(Attendance::getTimestamp) - .map(LocalDateTime::toString) - .collect(Collectors.toList()); - return timestamps; - } - private List findRecentAttendances(Long lectureId, Long studentId) { LocalDateTime now = seoulDateTimeHolder.getSeoulDateTime(); LocalDateTime beforeRecentTime = now.minusHours(RECENT_TIME.toHours()); @@ -127,13 +119,22 @@ private List findRecentAttendances(Long lectureId, Long studentId) { return attendances; } - private List getTimestamps(List attendanceHistories) { - return attendanceHistories.stream() + private List getTimestamps(AttendanceHistories attendanceHistories) { + return attendanceHistories.getHistories() + .stream() .map(AttendanceHistory::getTimestamp) .map(Objects::toString) .collect(Collectors.toList()); } + private List getRecentAttendanceTimestamps(Long lectureId, Long studentId) { + List attendances = findRecentAttendances(lectureId, studentId); + List timestamps = attendances.stream() + .map(Attendance::getTimestamp) + .map(LocalDateTime::toString) + .collect(Collectors.toList()); + return timestamps; + } private void validateLectureOpen(EnrollmentInfo enrollmentInfo) { if (enrollmentInfo.getLecture().getLectureState() != LectureState.OPEN) { diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java index 56d56d7..9420413 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java @@ -1,11 +1,11 @@ package gdsc.binaryho.imhere.core.attendance.application.port; +import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; -import java.util.List; public interface AttendanceHistoryCacheRepository { - List findAllByLectureIdAndStudentId(long lectureId, long studentId); + AttendanceHistories findAllByLectureIdAndStudentId(long lectureId, long studentId); void cache(AttendanceHistory attendanceHistory); } diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java new file mode 100644 index 0000000..ba7845e --- /dev/null +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java @@ -0,0 +1,21 @@ +package gdsc.binaryho.imhere.core.attendance.domain; + +import java.util.List; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class AttendanceHistories { + + private final List histories; + + public static AttendanceHistories of(List attendanceHistories) { + return new AttendanceHistories(attendanceHistories); + } + + public boolean isNotEmpty() { + return !histories.isEmpty(); + } +} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java index 77a37cd..45dccb4 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java @@ -1,8 +1,8 @@ package gdsc.binaryho.imhere.core.attendance.infrastructure; import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; +import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; -import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -19,15 +19,16 @@ public class AttendanceRedisCacheRepository implements AttendanceHistoryCacheRep private final RedisTemplate redisTemplate; @Override - public List findAllByLectureIdAndStudentId( + public AttendanceHistories findAllByLectureIdAndStudentId( final long lectureId, final long studentId) { String key = AttendanceHistory.convertToKey(lectureId, studentId); - return redisTemplate.opsForSet() + return AttendanceHistories.of( + redisTemplate.opsForSet() .members(key) .stream() .map(timestamp -> AttendanceHistory.of(lectureId, studentId, timestamp)) - .collect(Collectors.toList()); + .collect(Collectors.toList())); } @Override diff --git a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java index a7e8d11..2c4bb34 100644 --- a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java +++ b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java @@ -1,6 +1,7 @@ package gdsc.binaryho.imhere.mock.fakerepository; import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; +import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; import java.util.Collections; import java.util.HashMap; @@ -15,12 +16,13 @@ public class FakeAttendanceHistoryCacheRepository implements AttendanceHistoryCa private final Map> data = new HashMap<>(); @Override - public List findAllByLectureIdAndStudentId(final long lectureId, final long studentId) { - return data.getOrDefault( - AttendanceHistory.convertToKey(lectureId, studentId), Collections.emptySet()) + public AttendanceHistories findAllByLectureIdAndStudentId(final long lectureId, final long studentId) { + List attendanceHistories = data.getOrDefault( + AttendanceHistory.convertToKey(lectureId, studentId), Collections.emptySet()) .stream() .map(timestamp -> new AttendanceHistory(lectureId, studentId, timestamp)) .collect(Collectors.toList()); + return AttendanceHistories.of(attendanceHistories); } @Override From 4156718eca0cd9061836755d8e6b88903a10718a Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sun, 17 Mar 2024 18:00:23 +0900 Subject: [PATCH 8/9] =?UTF-8?q?refactor=20:=20Look=20Aside=20=EC=9D=B4?= =?UTF-8?q?=ED=9B=84=20attend=EB=A5=BC=20=ED=98=B8=EC=B6=9C=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD=20(#118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/StudentAttendanceService.java | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java index cc9d122..2f797ab 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java @@ -58,14 +58,14 @@ public class StudentAttendanceService { public void takeAttendance(AttendanceRequest attendanceRequest, Long lectureId) { Member currentStudent = authenticationHelper.getCurrentMember(); - if (isOpenLectureCacheExist(currentStudent.getId(), lectureId)) { - Lecture lecture = lectureRepository.findById(lectureId) - .orElseThrow(() -> LectureNotFoundException.EXCEPTION); - attend(attendanceRequest, currentStudent, lecture); + if (isOpenLectureCacheNotExist(currentStudent.getId(), lectureId)) { + attendWithValidateEnrollment(attendanceRequest, currentStudent, lectureId); return; } - attendWithEnrollmentInfo(attendanceRequest, lectureId, currentStudent); + Lecture lecture = lectureRepository.findById(lectureId) + .orElseThrow(() -> LectureNotFoundException.EXCEPTION); + attend(attendanceRequest, currentStudent, lecture); } @Transactional(readOnly = true) @@ -95,19 +95,10 @@ public StudentAttendanceResponse getStudentDayAttendance(Long lectureId, Long mi return new StudentAttendanceResponse(attendances); } - private void attendWithEnrollmentInfo(AttendanceRequest attendanceRequest, Long lectureId, - Member currentStudent) { - EnrollmentInfo enrollmentInfo = enrollmentRepository - .findByMemberIdAndLectureIdAndEnrollmentState(currentStudent.getId(), lectureId, - EnrollmentState.APPROVAL) - .orElseThrow(() -> EnrollmentNotApprovedException.EXCEPTION); - validateLectureOpen(enrollmentInfo); - attend(attendanceRequest, enrollmentInfo.getMember(), enrollmentInfo.getLecture()); + private boolean isOpenLectureCacheNotExist(Long studentId, Long lectureId) { + return !openLectureService.isStudentOpenLectureExist(studentId, lectureId); } - private boolean isOpenLectureCacheExist(Long studentId, Long lectureId) { - return openLectureService.isStudentOpenLectureExist(studentId, lectureId); - } private List findRecentAttendances(Long lectureId, Long studentId) { LocalDateTime now = seoulDateTimeHolder.getSeoulDateTime(); @@ -149,19 +140,20 @@ private void validateAttendanceNumber(Long lectureId, int attendanceNumber) { validateAttendanceNumberCorrect(actualAttendanceNumber, attendanceNumber); } - private void attend(AttendanceRequest attendanceRequest, EnrollmentInfo enrollmentInfo) { - Member student = enrollmentInfo.getMember(); - Lecture lecture = enrollmentInfo.getLecture(); - Attendance attendance = Attendance.createAttendance( - student, lecture, - attendanceRequest.getDistance(), - attendanceRequest.getAccuracy(), - seoulDateTimeHolder.from(attendanceRequest.getMilliseconds()) - ); - attendanceRepository.save(attendance); - publishStudentAttendedEvent(attendance, lecture, student); - logAttendanceHistory(enrollmentInfo.getMember(), attendance); + // 이거 그냥 Lecture를 확인하면 되는거 아닌가? -> 아냐 + private void attendWithValidateEnrollment( + AttendanceRequest attendanceRequest, Member student, Long lectureId) { + EnrollmentInfo enrollmentInfo = findApprovalEnrollment(lectureId, student); + validateLectureOpen(enrollmentInfo); + attend(attendanceRequest, enrollmentInfo.getMember(), enrollmentInfo.getLecture()); + } + + private EnrollmentInfo findApprovalEnrollment(Long lectureId, Member student) { + return enrollmentRepository + .findByMemberIdAndLectureIdAndEnrollmentState( + student.getId(), lectureId, EnrollmentState.APPROVAL) + .orElseThrow(() -> EnrollmentNotApprovedException.EXCEPTION); } private void attend(AttendanceRequest attendanceRequest, Member student, Lecture lecture) { From cc082709c7d5ced3c7a671b1e44a317546219a10 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Tue, 24 Sep 2024 22:51:35 +0900 Subject: [PATCH 9/9] refactor : async attendance --- .../imhere/config/redis/RedisConfig.java | 3 +- .../application/AttendanceFailedEvent.java | 13 +++ .../AttendanceHistoryCacheService.java | 42 ++++++- .../application/AttendanceRequestedEvent.java | 12 ++ .../AttendanceSaveRequestStatus.java | 53 +++++++++ .../application/AttendanceSaveService.java | 32 ++++++ .../AttendanceSaveSucceedEvent.java | 12 ++ .../application/StudentAttendanceService.java | 104 +++++++++--------- .../application/StudentAttendedEvent.java | 14 --- .../AttendanceHistoryCacheRepository.java | 6 +- .../controller/AttendanceController.java | 2 +- .../domain/AttendanceHistories.java | 21 ---- .../attendance/domain/AttendanceHistory.java | 19 +++- .../AttendanceHistoryCacheStrategy.java | 10 ++ .../AttendanceRedisCacheRepository.java | 10 +- .../StudentRecentAttendanceResponse.java | 12 +- .../lecture/application/LectureService.java | 19 ++++ src/main/resources/application-dev.yml | 6 +- .../FakeAttendanceHistoryCacheRepository.java | 10 +- .../AttendanceControllerTest.java | 2 +- src/test/resources/application.yml | 25 +++-- 21 files changed, 311 insertions(+), 116 deletions(-) create mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceFailedEvent.java create mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceRequestedEvent.java create mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveRequestStatus.java create mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveService.java create mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveSucceedEvent.java delete mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendedEvent.java delete mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java create mode 100644 src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceHistoryCacheStrategy.java diff --git a/src/main/java/gdsc/binaryho/imhere/config/redis/RedisConfig.java b/src/main/java/gdsc/binaryho/imhere/config/redis/RedisConfig.java index 6ae90bc..d5fb636 100644 --- a/src/main/java/gdsc/binaryho/imhere/config/redis/RedisConfig.java +++ b/src/main/java/gdsc/binaryho/imhere/config/redis/RedisConfig.java @@ -23,7 +23,8 @@ public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory() { - RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisHost, redisPort); +// RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisHost, redisPort); + RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration("localhost", 6379); configuration.setPassword(redisPassword); return new LettuceConnectionFactory(configuration); diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceFailedEvent.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceFailedEvent.java new file mode 100644 index 0000000..0e841ac --- /dev/null +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceFailedEvent.java @@ -0,0 +1,13 @@ +package gdsc.binaryho.imhere.core.attendance.application; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class AttendanceFailedEvent { + + private final long lectureId; + private final long studentId; + private final Throwable exception; +} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceHistoryCacheService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceHistoryCacheService.java index 23d216f..5d632b8 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceHistoryCacheService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceHistoryCacheService.java @@ -1,8 +1,13 @@ package gdsc.binaryho.imhere.core.attendance.application; +import static gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory.createAcceptedAttendanceHistory; +import static gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory.createAwaitAttendanceHistory; +import static gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory.createFailedAttendanceHistory; + import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; @@ -10,6 +15,7 @@ import org.springframework.transaction.event.TransactionPhase; import org.springframework.transaction.event.TransactionalEventListener; +@Log4j2 @Service @RequiredArgsConstructor public class AttendanceHistoryCacheService { @@ -19,13 +25,41 @@ public class AttendanceHistoryCacheService { @Async @Transactional(propagation = Propagation.REQUIRES_NEW) @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) - public void cache(StudentAttendedEvent event) { + public void cacheAttendanceHistory(AttendanceRequestedEvent event) { long lectureId = event.getLectureId(); long studentId = event.getStudentId(); - String timestamp = event.getTimestamp().toString(); - AttendanceHistory attendanceHistory = AttendanceHistory.of( - lectureId, studentId, timestamp); + AttendanceHistory attendanceHistory = createAwaitAttendanceHistory(lectureId, studentId); attendanceHistoryCacheRepository.cache(attendanceHistory); } + + @Async + @Transactional(propagation = Propagation.REQUIRES_NEW) + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void saveAttendance(AttendanceSaveSucceedEvent event) { + long lectureId = event.getLectureId(); + long studentId = event.getStudentId(); + + AttendanceHistory attendanceHistory = createAcceptedAttendanceHistory(lectureId, studentId); + attendanceHistoryCacheRepository.cache(attendanceHistory); + } + + @Async + @Transactional(propagation = Propagation.REQUIRES_NEW) + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void saveAttendance(AttendanceFailedEvent event) { + long lectureId = event.getLectureId(); + long studentId = event.getStudentId(); + + AttendanceHistory attendanceHistory = createFailedAttendanceHistory(lectureId, studentId); + attendanceHistoryCacheRepository.cache(attendanceHistory); + logAttendanceFailed(studentId, lectureId, event.getException()); + } + + private void logAttendanceFailed(Long studentId, Long lectureId, RuntimeException exception) { + String exceptionName = exception.getClass().getName(); + String exceptionMessage = exception.getMessage(); + log.info("[출석 실패] 학생 id {}, 수업 id : {}, 예외 이름 : {}, 예외 메시지 : {}", + studentId, lectureId, exceptionName, exceptionMessage); + } } diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceRequestedEvent.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceRequestedEvent.java new file mode 100644 index 0000000..020b666 --- /dev/null +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceRequestedEvent.java @@ -0,0 +1,12 @@ +package gdsc.binaryho.imhere.core.attendance.application; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class AttendanceRequestedEvent { + + private final long lectureId; + private final long studentId; +} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveRequestStatus.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveRequestStatus.java new file mode 100644 index 0000000..7248154 --- /dev/null +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveRequestStatus.java @@ -0,0 +1,53 @@ +package gdsc.binaryho.imhere.core.attendance.application; + +import org.springframework.data.redis.core.RedisTemplate; + +public enum AttendanceSaveRequestStatus { + + /* + * 또한, 설문을 통해 유저들이 요청한 “출석 성공 조회”기능을 위해, 출석 요청, 성공, 예외 발생시 이벤트를 발행해 캐싱한다. + * 출석 성공은 다른 상태를 덮어 쓰고, 다른 상태는 출석 성공을 덮어 쓸 수 없다. + * */ + + PROCESSING { + @Override + public void cache( + RedisTemplate redisTemplate, String key, String value) { + String savedValue = redisTemplate.opsForValue().getAndDelete(key); + if (SUCCESS.name().equals(savedValue)) + redisTemplate.opsForValue().set(key, value); + } + }, + + SUCCESS { + @Override + public void cache( + RedisTemplate redisTemplate, String key, String value) { + String savedValue = redisTemplate.opsForValue().getAndDelete(key); + redisTemplate.opsForValue().set(key, savedValue, value); + } + }, + + FAILED { + @Override + public void cache( + RedisTemplate redisTemplate, String key, String value) { + redisTemplate.opsForSet().add(key, value); + } + }, + + NO_REQUEST { + @Override + public void cache( + RedisTemplate redisTemplate, String key, String value) { + redisTemplate.opsForSet().add(key, value); + } + }; + + public abstract void cache( + RedisTemplate redisTemplate, String key, String value); + + public boolean canCache(String originalValue) { + this.name() + } +} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveService.java new file mode 100644 index 0000000..3638a36 --- /dev/null +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveService.java @@ -0,0 +1,32 @@ +package gdsc.binaryho.imhere.core.attendance.application; + +import gdsc.binaryho.imhere.core.attendance.domain.Attendance; +import gdsc.binaryho.imhere.core.attendance.infrastructure.AttendanceRepository; +import gdsc.binaryho.imhere.core.lecture.domain.Lecture; +import gdsc.binaryho.imhere.core.member.Member; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Log4j2 +@Service +@RequiredArgsConstructor +public class AttendanceSaveService { + + private final AttendanceRepository attendanceRepository; + + @Transactional + public void save(Attendance attendance) { + attendanceRepository.save(attendance); + logAttendanceHistory(attendance); + } + + private void logAttendanceHistory(Attendance attendance) { + Member student = attendance.getStudent(); + Lecture lecture = attendance.getLecture(); + log.info("[출석 완료] {}({}) , 학생 : {} ({})", + lecture::getLectureName, lecture::getId, + student::getUnivId, student::getName); + } +} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveSucceedEvent.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveSucceedEvent.java new file mode 100644 index 0000000..934e9bd --- /dev/null +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/AttendanceSaveSucceedEvent.java @@ -0,0 +1,12 @@ +package gdsc.binaryho.imhere.core.attendance.application; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class AttendanceSaveSucceedEvent { + + private final long lectureId; + private final long studentId; +} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java index 2f797ab..c3dcd85 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendanceService.java @@ -1,10 +1,11 @@ package gdsc.binaryho.imhere.core.attendance.application; +import static gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus.NO_REQUEST; +import static gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus.SUCCESS; + import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; import gdsc.binaryho.imhere.core.attendance.domain.Attendance; -import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; -import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; import gdsc.binaryho.imhere.core.attendance.exception.AttendanceNumberIncorrectException; import gdsc.binaryho.imhere.core.attendance.exception.AttendanceTimeExceededException; import gdsc.binaryho.imhere.core.attendance.infrastructure.AttendanceRepository; @@ -27,20 +28,18 @@ import java.time.Duration; import java.time.LocalDateTime; import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; +import java.util.concurrent.CompletableFuture; import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -@Log4j2 @Service @RequiredArgsConstructor public class StudentAttendanceService { private final OpenLectureService openLectureService; + private final AttendanceSaveService attendanceSaveService; private final LectureRepository lectureRepository; private final AttendanceRepository attendanceRepository; @@ -69,19 +68,27 @@ public void takeAttendance(AttendanceRequest attendanceRequest, Long lectureId) } @Transactional(readOnly = true) - public StudentRecentAttendanceResponse getStudentRecentAttendance(Long lectureId) { + public StudentRecentAttendanceResponse getStudentRecentAttendanceStatus(Long lectureId) { Long studentId = authenticationHelper.getCurrentMember().getId(); + AttendanceSaveRequestStatus attendanceSaveRequestStatus = attendanceHistoryCacheRepository + .getRequestStatusByLectureIdAndStudentId(lectureId, studentId); - AttendanceHistories attendanceHistories = attendanceHistoryCacheRepository - .findAllByLectureIdAndStudentId(lectureId, studentId); - - if (attendanceHistories.isNotEmpty()) { - List timestamps = getTimestamps(attendanceHistories); - return new StudentRecentAttendanceResponse(timestamps); + if (isRequestExist(attendanceSaveRequestStatus)) { + return new StudentRecentAttendanceResponse(attendanceSaveRequestStatus); } - List timestamps = getRecentAttendanceTimestamps(lectureId, studentId); - return new StudentRecentAttendanceResponse(timestamps); + return getStudentRecentAttendanceStatus(lectureId, studentId); + } + + private boolean isRequestExist(AttendanceSaveRequestStatus attendanceSaveRequestStatus) { + return !attendanceSaveRequestStatus.equals(NO_REQUEST); + } + + private StudentRecentAttendanceResponse getStudentRecentAttendanceStatus(Long lectureId, Long studentId) { + if (isRecentAttendancesExist(lectureId, studentId)) { + return new StudentRecentAttendanceResponse(SUCCESS); + } + return new StudentRecentAttendanceResponse(NO_REQUEST); } @Transactional(readOnly = true) @@ -99,32 +106,14 @@ private boolean isOpenLectureCacheNotExist(Long studentId, Long lectureId) { return !openLectureService.isStudentOpenLectureExist(studentId, lectureId); } - - private List findRecentAttendances(Long lectureId, Long studentId) { + private Boolean isRecentAttendancesExist(Long lectureId, Long studentId) { LocalDateTime now = seoulDateTimeHolder.getSeoulDateTime(); LocalDateTime beforeRecentTime = now.minusHours(RECENT_TIME.toHours()); List attendances = attendanceRepository .findByLectureIdAndStudentIdAndTimestampBetween( lectureId, studentId, beforeRecentTime, now); - return attendances; - } - - private List getTimestamps(AttendanceHistories attendanceHistories) { - return attendanceHistories.getHistories() - .stream() - .map(AttendanceHistory::getTimestamp) - .map(Objects::toString) - .collect(Collectors.toList()); - } - - private List getRecentAttendanceTimestamps(Long lectureId, Long studentId) { - List attendances = findRecentAttendances(lectureId, studentId); - List timestamps = attendances.stream() - .map(Attendance::getTimestamp) - .map(LocalDateTime::toString) - .collect(Collectors.toList()); - return timestamps; + return !attendances.isEmpty(); } private void validateLectureOpen(EnrollmentInfo enrollmentInfo) { @@ -140,8 +129,6 @@ private void validateAttendanceNumber(Long lectureId, int attendanceNumber) { validateAttendanceNumberCorrect(actualAttendanceNumber, attendanceNumber); } - - // 이거 그냥 Lecture를 확인하면 되는거 아닌가? -> 아냐 private void attendWithValidateEnrollment( AttendanceRequest attendanceRequest, Member student, Long lectureId) { EnrollmentInfo enrollmentInfo = findApprovalEnrollment(lectureId, student); @@ -166,23 +153,40 @@ private void attend(AttendanceRequest attendanceRequest, Member student, Lecture seoulDateTimeHolder.from(attendanceRequest.getMilliseconds()) ); - attendanceRepository.save(attendance); - publishStudentAttendedEvent(attendance, lecture, student); - logAttendanceHistory(student, attendance); + saveAttendanceAsynchronously(attendance); + publishAttendanceRequestedEvent(attendance); } - private void publishStudentAttendedEvent( - Attendance attendance, Lecture lecture, Member student) { - LocalDateTime timestamp = attendance.getTimestamp(); - eventPublisher.publishEvent( - new StudentAttendedEvent(lecture.getId(), student.getId(), timestamp)); + private void saveAttendanceAsynchronously(Attendance attendance) { + CompletableFuture.runAsync( + () -> attendanceSaveService.save(attendance) + ).thenRun( + () -> publishAttendanceSaveSucceedEvent(attendance) + ).exceptionally( + exception -> publishAttendanceFailedEvent(attendance, exception) + ); } - private void logAttendanceHistory(Member student, Attendance attendance) { - Lecture lecture = attendance.getLecture(); - log.info("[출석 완료] {}({}) , 학생 : {} ({})", - lecture::getLectureName, lecture::getId, - student::getUnivId, student::getName); + private void publishAttendanceSaveSucceedEvent(Attendance attendance) { + Long lectureId = attendance.getLecture().getId(); + Long studentId = attendance.getStudent().getId(); + AttendanceSaveSucceedEvent event = new AttendanceSaveSucceedEvent(lectureId, studentId); + eventPublisher.publishEvent(event); + } + + private Void publishAttendanceFailedEvent(Attendance attendance, Throwable throwable) { + Long lectureId = attendance.getLecture().getId(); + Long studentId = attendance.getStudent().getId(); + AttendanceFailedEvent event = new AttendanceFailedEvent(lectureId, studentId, throwable); + eventPublisher.publishEvent(event); + return null; + } + + private void publishAttendanceRequestedEvent(Attendance attendance) { + Long lectureId = attendance.getLecture().getId(); + Long studentId = attendance.getStudent().getId(); + eventPublisher.publishEvent( + new AttendanceRequestedEvent(lectureId, studentId)); } private void validateAttendanceNumberNotTimeOut(Integer attendanceNumber) { diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendedEvent.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendedEvent.java deleted file mode 100644 index 608b8ea..0000000 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/StudentAttendedEvent.java +++ /dev/null @@ -1,14 +0,0 @@ -package gdsc.binaryho.imhere.core.attendance.application; - -import java.time.LocalDateTime; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class StudentAttendedEvent { - - private final long lectureId; - private final long studentId; - private final LocalDateTime timestamp; -} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java index 9420413..b35c134 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/application/port/AttendanceHistoryCacheRepository.java @@ -1,11 +1,11 @@ package gdsc.binaryho.imhere.core.attendance.application.port; -import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; +import gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; public interface AttendanceHistoryCacheRepository { - AttendanceHistories findAllByLectureIdAndStudentId(long lectureId, long studentId); - void cache(AttendanceHistory attendanceHistory); + + AttendanceSaveRequestStatus getRequestStatusByLectureIdAndStudentId(Long lectureId, Long studentId); } diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/controller/AttendanceController.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/controller/AttendanceController.java index fd009fb..2288bc0 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/controller/AttendanceController.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/controller/AttendanceController.java @@ -58,7 +58,7 @@ public ResponseEntity getStudentDayAttendance( public ResponseEntity getStudentRecentAttendance( @PathVariable("lecture_id") Long lectureId) { return ResponseEntity.ok( - studentAttendanceService.getStudentRecentAttendance(lectureId)); + studentAttendanceService.getStudentRecentAttendanceStatus(lectureId)); } @Operation(summary = "강사가 지정 강의의 출석 정보 전체를 가져오는 API") diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java deleted file mode 100644 index ba7845e..0000000 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistories.java +++ /dev/null @@ -1,21 +0,0 @@ -package gdsc.binaryho.imhere.core.attendance.domain; - -import java.util.List; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) -public class AttendanceHistories { - - private final List histories; - - public static AttendanceHistories of(List attendanceHistories) { - return new AttendanceHistories(attendanceHistories); - } - - public boolean isNotEmpty() { - return !histories.isEmpty(); - } -} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistory.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistory.java index c634350..93c4711 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistory.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/domain/AttendanceHistory.java @@ -1,6 +1,11 @@ package gdsc.binaryho.imhere.core.attendance.domain; +import static gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus.SUCCESS; +import static gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus.PROCESSING; +import static gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus.FAILED; + import gdsc.binaryho.imhere.config.redis.RedisKeyConstants; +import gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus; import gdsc.binaryho.imhere.domain.CacheEntity; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -13,10 +18,18 @@ public class AttendanceHistory extends CacheEntity { private final long lectureId; private final long studentId; - private final String timestamp; + private final AttendanceSaveRequestStatus attendanceSaveRequestStatus; + + public static AttendanceHistory createAwaitAttendanceHistory(long lectureId, long studentId) { + return new AttendanceHistory(lectureId, studentId, PROCESSING); + } + + public static AttendanceHistory createAcceptedAttendanceHistory(long lectureId, long studentId) { + return new AttendanceHistory(lectureId, studentId, SUCCESS); + } - public static AttendanceHistory of(long lectureId, long studentId, String timestamp) { - return new AttendanceHistory(lectureId, studentId, timestamp); + public static AttendanceHistory createFailedAttendanceHistory(long lectureId, long studentId) { + return new AttendanceHistory(lectureId, studentId, FAILED); } @Override diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceHistoryCacheStrategy.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceHistoryCacheStrategy.java new file mode 100644 index 0000000..9ee46cc --- /dev/null +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceHistoryCacheStrategy.java @@ -0,0 +1,10 @@ +package gdsc.binaryho.imhere.core.attendance.infrastructure; + +import gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus; + +public class AttendanceHistoryCacheStrategy { + + public boolean canCache(AttendanceSaveRequestStatus newValue) { + + } +} diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java index 45dccb4..c66ac5f 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/infrastructure/AttendanceRedisCacheRepository.java @@ -1,7 +1,7 @@ package gdsc.binaryho.imhere.core.attendance.infrastructure; +import gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus; import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; -import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -33,9 +33,17 @@ public AttendanceHistories findAllByLectureIdAndStudentId( @Override public void cache(AttendanceHistory attendanceHistory) { + attendanceHistory.getAttendanceSaveRequestStatus(); String key = attendanceHistory.getKey(); + String savedStatus = redisTemplate.opsForValue().get(key); redisTemplate.opsForSet() .add(key, attendanceHistory.getTimestamp()); redisTemplate.expire(key, ATTENDANCE_HISTORY_EXPIRE_HOUR, TimeUnit.HOURS); } + + @Override + public AttendanceSaveRequestStatus getRequestStatusByLectureIdAndStudentId(Long lectureId, + Long studentId) { + return null; + } } diff --git a/src/main/java/gdsc/binaryho/imhere/core/attendance/model/response/StudentRecentAttendanceResponse.java b/src/main/java/gdsc/binaryho/imhere/core/attendance/model/response/StudentRecentAttendanceResponse.java index d8c5182..5016761 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/attendance/model/response/StudentRecentAttendanceResponse.java +++ b/src/main/java/gdsc/binaryho/imhere/core/attendance/model/response/StudentRecentAttendanceResponse.java @@ -1,14 +1,16 @@ package gdsc.binaryho.imhere.core.attendance.model.response; +import gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus; import io.swagger.v3.oas.annotations.tags.Tag; -import java.util.List; import lombok.Getter; -import lombok.RequiredArgsConstructor; @Getter -@RequiredArgsConstructor -@Tag(name = "StudentRecentAttendanceResponse", description = "학생의 최근 출석 시간들") +@Tag(name = "StudentRecentAttendanceResponse", description = "학생의 최근 출석 상태") public class StudentRecentAttendanceResponse { - private final List timestamps; + private final String recentAttendanceStatus; + + public StudentRecentAttendanceResponse(AttendanceSaveRequestStatus status) { + this.recentAttendanceStatus = status.name(); + } } diff --git a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java index a1aafde..b5835f4 100644 --- a/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java +++ b/src/main/java/gdsc/binaryho/imhere/core/lecture/application/LectureService.java @@ -142,6 +142,25 @@ public AttendanceNumberResponse openLectureAndGenerateAttendanceNumber(Long lect return new AttendanceNumberResponse(attendanceNumber); } + // TODO : 테스트용 + @Transactional + public AttendanceNumberResponse openLectureAndGenerateAttendanceNumber(Long lectureId, int attendanceNumber) { + Lecture lecture = lectureRepository.findById(lectureId) + .orElseThrow(() -> LectureNotFoundException.EXCEPTION); +// authenticationHelper.verifyRequestMemberLogInMember(lecture.getMember().getId()); + + lecture.setLectureState(LectureState.OPEN); + lecture.setLastOpeningTime(seoulDateTimeHolder.getSeoulDateTime()); + + saveOpenLecture(lecture, attendanceNumber); + cacheAttendee(lecture); + + log.info("[강의 OPEN] {} ({}), 출석 번호 : " + attendanceNumber + , lecture::getLectureName, lecture::getId); + + return new AttendanceNumberResponse(attendanceNumber); + } + private void saveOpenLecture(Lecture lecture, int attendanceNumber) { OpenLecture openLecture = OpenLecture.of(lecture, attendanceNumber); openLectureCacheRepository.cache(openLecture); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index f453f60..d724050 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -23,9 +23,9 @@ spring: ddl-auto: none dialect: -- org.hibernate.dialect.PostgreSQLDialect - properties: - hibernate: - format_sql: true +# properties: +# hibernate: +# format_sql: true logging.level: org.hibernate.SQL: debug diff --git a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java index 2c4bb34..28aa41d 100644 --- a/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java +++ b/src/test/java/gdsc/binaryho/imhere/mock/fakerepository/FakeAttendanceHistoryCacheRepository.java @@ -1,7 +1,7 @@ package gdsc.binaryho.imhere.mock.fakerepository; +import gdsc.binaryho.imhere.core.attendance.application.AttendanceSaveRequestStatus; import gdsc.binaryho.imhere.core.attendance.application.port.AttendanceHistoryCacheRepository; -import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistories; import gdsc.binaryho.imhere.core.attendance.domain.AttendanceHistory; import java.util.Collections; import java.util.HashMap; @@ -29,4 +29,12 @@ public AttendanceHistories findAllByLectureIdAndStudentId(final long lectureId, public void cache(AttendanceHistory attendanceHistory) { data.putIfAbsent(attendanceHistory.getKey(), new HashSet<>()); } + + @Override + public AttendanceSaveRequestStatus getRequestStatusByLectureIdAndStudentId( + Long lectureId, Long studentId) { + + data.getOrDefault(AttendanceHistory.convertToKey(lectureId, studentId)) + return null; + } } diff --git a/src/test/java/gdsc/binaryho/imhere/presentation/AttendanceControllerTest.java b/src/test/java/gdsc/binaryho/imhere/presentation/AttendanceControllerTest.java index 53ae82a..c3f63b5 100644 --- a/src/test/java/gdsc/binaryho/imhere/presentation/AttendanceControllerTest.java +++ b/src/test/java/gdsc/binaryho/imhere/presentation/AttendanceControllerTest.java @@ -79,7 +79,7 @@ public class AttendanceControllerTest { long milliseconds = MOCK_ATTENDANCE.getTimestamp().toInstant(ZoneOffset.UTC).toEpochMilli(); StudentRecentAttendanceResponse response = new StudentRecentAttendanceResponse( List.of(MOCK_ATTENDANCE.getTimestamp().toString())); - given(studentAttendanceService.getStudentRecentAttendance(lectureId)) + given(studentAttendanceService.getStudentRecentAttendanceStatus(lectureId)) .willReturn(response); mockMvc.perform( diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index b834b61..7ac40ca 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -13,17 +13,26 @@ spring: jpa: open-in-view: false + hibernate: + ddl-auto: none + # 원본 - h2: - console: - enabled: true - path: /h2-console +# h2: +# console: +# enabled: true +# path: /h2-console +# datasource: +# url: jdbc:h2:~/mem-data; +# driverClassName: org.h2.Driver +# username: sa +# password: + datasource: - url: jdbc:h2:~/mem-data; - driverClassName: org.h2.Driver - username: sa - password: + url: jdbc:postgresql://jinho-database.ckddmrlccdc1.ap-northeast-2.rds.amazonaws.com:5432/imhere-dev + username: postgres + password: d0YhFa6o3HJ8GqOzKhF5 +# driver-class-name: org.postgresql.Drive redis: host: localhost