From 9484e65dda4c8f8af68588e7155277506ecec0c9 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 01:07:30 +0900 Subject: [PATCH 01/19] =?UTF-8?q?[REFACTOR]=20DTO=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/lecture/AttendanceResponseDTO.java | 5 +- .../dto/lecture/LectureRequestDTO.java | 1 + .../dto/lecture/LectureResponseDTO.java | 31 +++++++--- .../dto/lecture/LecturesResponseDTO.java | 62 +++++++++---------- 4 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java b/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java index 9376a41a..da99b041 100644 --- a/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java +++ b/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java @@ -1,4 +1,7 @@ package org.sopt.makers.operation.dto.lecture; -public record AttendanceResponseDTO(Long lectureId, Long subLectureId) { +public record AttendanceResponseDTO( + Long lectureId, + Long subLectureId +) { } diff --git a/src/main/java/org/sopt/makers/operation/dto/lecture/LectureRequestDTO.java b/src/main/java/org/sopt/makers/operation/dto/lecture/LectureRequestDTO.java index 970f1f76..96c99649 100644 --- a/src/main/java/org/sopt/makers/operation/dto/lecture/LectureRequestDTO.java +++ b/src/main/java/org/sopt/makers/operation/dto/lecture/LectureRequestDTO.java @@ -9,6 +9,7 @@ import lombok.*; +@Builder public record LectureRequestDTO( @NonNull Part part, @NonNull String name, diff --git a/src/main/java/org/sopt/makers/operation/dto/lecture/LectureResponseDTO.java b/src/main/java/org/sopt/makers/operation/dto/lecture/LectureResponseDTO.java index 69e90313..81a07c6b 100644 --- a/src/main/java/org/sopt/makers/operation/dto/lecture/LectureResponseDTO.java +++ b/src/main/java/org/sopt/makers/operation/dto/lecture/LectureResponseDTO.java @@ -1,6 +1,8 @@ package org.sopt.makers.operation.dto.lecture; import static java.util.Objects.*; + +import java.time.LocalDateTime; import java.util.List; import org.sopt.makers.operation.entity.Part; @@ -35,16 +37,25 @@ public static LectureResponseDTO of(Lecture lecture) { .status(lecture.getLectureStatus()) .build(); } -} -record SubLectureVO( - Long subLectureId, - int round, - String startAt, - String code -) { - static SubLectureVO of(SubLecture subLecture) { - val startAt = nonNull(subLecture.getStartAt()) ? subLecture.getStartAt().toString() : null; - return new SubLectureVO(subLecture.getId(), subLecture.getRound(), startAt, subLecture.getCode()); + @Builder + public record SubLectureVO( + Long subLectureId, + int round, + String startAt, + String code + ) { + private static SubLectureVO of(SubLecture subLecture) { + return SubLectureVO.builder() + .subLectureId(subLecture.getId()) + .round(subLecture.getRound()) + .startAt(getStartAt(subLecture.getStartAt())) + .code(subLecture.getCode()) + .build(); + } + + private static String getStartAt(LocalDateTime startAt) { + return nonNull(startAt) ? startAt.toString() : null; + } } } \ No newline at end of file diff --git a/src/main/java/org/sopt/makers/operation/dto/lecture/LecturesResponseDTO.java b/src/main/java/org/sopt/makers/operation/dto/lecture/LecturesResponseDTO.java index 253a9f25..2a831d19 100644 --- a/src/main/java/org/sopt/makers/operation/dto/lecture/LecturesResponseDTO.java +++ b/src/main/java/org/sopt/makers/operation/dto/lecture/LecturesResponseDTO.java @@ -9,44 +9,44 @@ import lombok.*; public record LecturesResponseDTO( - int generation, - List lectures + int generation, + List lectures ) { public static LecturesResponseDTO of(int generation, List lectures) { return new LecturesResponseDTO( - generation, - lectures.stream().map(LectureVO::of).toList() + generation, + lectures.stream().map(LectureVO::of).toList() ); } -} -@Builder -record LectureVO( - Long lectureId, - String name, - Part partValue, - String partName, - String startDate, - String endDate, - Attribute attributeValue, - String attributeName, - String place, - AttendancesStatusVO attendances -) { - public static LectureVO of(Lecture lecture) { - return LectureVO.builder() - .lectureId(lecture.getId()) - .name(lecture.getName()) - .partValue(lecture.getPart()) - .partName(lecture.getPart().getName()) - .startDate(lecture.getStartDate().toString()) - .endDate(lecture.getEndDate().toString()) - .attributeValue(lecture.getAttribute()) - .attributeName(lecture.getAttribute().getName()) - .place(lecture.getPlace()) - .attendances(AttendancesStatusVO.of(lecture)) - .build(); + @Builder + public record LectureVO( + Long lectureId, + String name, + Part partValue, + String partName, + String startDate, + String endDate, + Attribute attributeValue, + String attributeName, + String place, + AttendancesStatusVO attendances + ) { + private static LectureVO of(Lecture lecture) { + return LectureVO.builder() + .lectureId(lecture.getId()) + .name(lecture.getName()) + .partValue(lecture.getPart()) + .partName(lecture.getPart().getName()) + .startDate(lecture.getStartDate().toString()) + .endDate(lecture.getEndDate().toString()) + .attributeValue(lecture.getAttribute()) + .attributeName(lecture.getAttribute().getName()) + .place(lecture.getPlace()) + .attendances(AttendancesStatusVO.of(lecture)) + .build(); + } } } From 2275e9e997e166804a52cf9585dfbb9b57809a68 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 01:08:13 +0900 Subject: [PATCH 02/19] =?UTF-8?q?[REFACTOR]=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/LectureController.java | 42 +++++++++---------- .../operation/service/LectureServiceImpl.java | 1 - 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java b/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java index 1fdd49db..43d57790 100644 --- a/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java +++ b/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java @@ -1,5 +1,6 @@ package org.sopt.makers.operation.controller.web; +import static org.sopt.makers.operation.common.ApiResponse.*; import static org.sopt.makers.operation.common.ResponseMessage.*; import java.net.URI; @@ -39,22 +40,21 @@ public ResponseEntity createLecture(@RequestBody LectureRequestDTO val lectureId = lectureService.createLecture(requestDTO); return ResponseEntity .created(getURI(lectureId)) - .body(ApiResponse.success(SUCCESS_CREATE_LECTURE.getMessage(), lectureId)); + .body(success(SUCCESS_CREATE_LECTURE.getMessage(), lectureId)); } @ApiOperation(value = "세션 리스트 조회") @GetMapping - public ResponseEntity getLecturesByGeneration( - @RequestParam("generation") int generation, @RequestParam(required = false) Part part) { + public ResponseEntity getLecturesByGeneration(@RequestParam int generation, @RequestParam(required = false) Part part) { val response = lectureService.getLecturesByGeneration(generation, part); - return ResponseEntity.ok(ApiResponse.success(SUCCESS_GET_LECTURES.getMessage(), response)); + return ResponseEntity.ok(success(SUCCESS_GET_LECTURES.getMessage(), response)); } - @ApiOperation(value = "세션 상세 조회") + @ApiOperation(value = "세션 단일 조회") @GetMapping("/{lectureId}") public ResponseEntity getLecture(@PathVariable Long lectureId) { val response = lectureService.getLecture(lectureId); - return ResponseEntity.ok(ApiResponse.success(SUCCESS_GET_LECTURE.getMessage(), response)); + return ResponseEntity.ok(success(SUCCESS_GET_LECTURE.getMessage(), response)); } @ApiOperation(value = "출석 시작") @@ -63,35 +63,35 @@ public ResponseEntity startAttendance(@RequestBody AttendanceReques val response = lectureService.startAttendance(requestDTO); return ResponseEntity .created(getURI(requestDTO.lectureId())) - .body(ApiResponse.success(SUCCESS_START_ATTENDANCE.getMessage(), response)); + .body(success(SUCCESS_START_ATTENDANCE.getMessage(), response)); } - @ApiOperation(value = "출석 점수 갱신 트리거 (출석 종료)") + private URI getURI(Long lectureId) { + return ServletUriComponentsBuilder + .fromCurrentRequest() + .path("/{lectureId}") + .buildAndExpand(lectureId) + .toUri(); + } + + @ApiOperation(value = "세션 종료 후 출석 점수 갱신") @PatchMapping("/{lectureId}") - public ResponseEntity finishLecture(@PathVariable("lectureId") Long lectureId) { + public ResponseEntity finishLecture(@PathVariable Long lectureId) { lectureService.finishLecture(lectureId); - return ResponseEntity.ok(ApiResponse.success(SUCCESS_UPDATE_MEMBER_SCORE.getMessage())); + return ResponseEntity.ok(success(SUCCESS_UPDATE_MEMBER_SCORE.getMessage())); } @ApiOperation(value = "세션 삭제") @DeleteMapping("/{lectureId}") public ResponseEntity deleteLecture(@PathVariable Long lectureId) { lectureService.deleteLecture(lectureId); - return ResponseEntity.ok(ApiResponse.success(SUCCESS_DELETE_LECTURE.getMessage())); + return ResponseEntity.ok(success(SUCCESS_DELETE_LECTURE.getMessage())); } - @ApiOperation(value = "세션 상세 조회 (팝업)") + @ApiOperation(value = "세션 팝업용 상세 조회") @GetMapping("/detail/{lectureId}") public ResponseEntity getLectureDetail(@PathVariable Long lectureId) { val response = lectureService.getLectureDetail(lectureId); - return ResponseEntity.ok(ApiResponse.success(SUCCESS_GET_LECTURE.getMessage(), response)); - } - - private URI getURI(Long lectureId) { - return ServletUriComponentsBuilder - .fromCurrentRequest() - .path("/{lectureId}") - .buildAndExpand(lectureId) - .toUri(); + return ResponseEntity.ok(success(SUCCESS_GET_LECTURE.getMessage(), response)); } } diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index edbc3cd3..6f405fde 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -141,7 +141,6 @@ public LectureGetResponseDTO getCurrentLecture(Long playGroundId) { return LectureGetResponseDTO.of(lectureType, currentLecture, message, subAttendances); } - @Override public LecturesResponseDTO getLecturesByGeneration(int generation, Part part) { val lectures = lectureRepository.findLectures(generation, part); From d556cb0a56753596706219637cb91017b21b7a9f Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 01:08:36 +0900 Subject: [PATCH 03/19] =?UTF-8?q?[TEST]=20=EC=84=B8=EC=85=98(web)=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 5 + .../controller/web/LectureControllerTest.java | 273 ++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java diff --git a/build.gradle b/build.gradle index 74b34945..a6ed1626 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" implementation "com.querydsl:querydsl-apt:${queryDslVersion}" + testImplementation 'junit:junit:4.13.1' + testImplementation 'junit:junit:4.13.1' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' @@ -48,6 +50,9 @@ dependencies { // swagger implementation 'io.springfox:springfox-boot-starter:3.0.0' implementation 'io.springfox:springfox-swagger-ui:3.0.0' + + // gson + implementation 'com.google.code.gson:gson:2.8.9' } tasks.named('test') { diff --git a/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java b/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java new file mode 100644 index 00000000..bf22b432 --- /dev/null +++ b/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java @@ -0,0 +1,273 @@ +package org.sopt.makers.operation.controller.web; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.sopt.makers.operation.dto.lecture.AttendanceRequestDTO; +import org.sopt.makers.operation.dto.lecture.AttendanceResponseDTO; +import org.sopt.makers.operation.dto.lecture.AttendancesStatusVO; +import org.sopt.makers.operation.dto.lecture.LectureDetailResponseDTO; +import org.sopt.makers.operation.dto.lecture.LectureRequestDTO; +import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; +import org.sopt.makers.operation.dto.lecture.LectureResponseDTO.SubLectureVO; +import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; +import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO.LectureVO; +import org.sopt.makers.operation.entity.Part; +import org.sopt.makers.operation.entity.lecture.Attribute; +import org.sopt.makers.operation.entity.lecture.LectureStatus; +import org.sopt.makers.operation.service.LectureService; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import com.google.gson.Gson; + +@ExtendWith(MockitoExtension.class) +class LectureControllerTest { + @InjectMocks + private LectureController lectureController; + + @Mock + private LectureService lectureService; + + private MockMvc mockMvc; + + private final String DEFAULT_URI = "/api/v1/lectures"; + private final String LECTURE_NAME = "테스트 이름"; + private final Part LECTURE_PART = Part.ALL; + private final int LECTURE_GENERATION = 30; + private final String LECTURE_PLACE = "테스트 장소"; + private final LocalDateTime NOW = LocalDateTime.now(); + private final Attribute LECTURE_ATTRIBUTE = Attribute.ETC; + private final LectureStatus LECTURE_STATUS = LectureStatus.BEFORE; + private final int LIST_SIZE = 5; + private final String SUB_LECTURE_CODE = "code"; + + @BeforeEach + public void init() { + mockMvc = MockMvcBuilders.standaloneSetup(lectureController).build(); + } + + @DisplayName("세션 생성 성공") + @Test + void success_createLecture() throws Exception { + // given + LectureRequestDTO request = lectureRequest(); + long response = lectureId(); + + doReturn(response).when(lectureService).createLecture(any()); + + // when + ResultActions resultActions = mockMvc.perform( + MockMvcRequestBuilders.post(DEFAULT_URI) + .contentType(MediaType.APPLICATION_JSON) + .content(new Gson().toJson(request))); + + // then + resultActions.andExpect(status().isCreated()); + } + + @DisplayName("세션 목록 조회 성공") + @Test + void success_getLectureList() throws Exception { + // given + LecturesResponseDTO response = lecturesResponse(); + MultiValueMap queries = new LinkedMultiValueMap<>(); + queries.add("generation", String.valueOf(LECTURE_GENERATION)); + + doReturn(response).when(lectureService).getLecturesByGeneration(anyInt(), any()); + + // when + ResultActions resultActions = mockMvc.perform( + MockMvcRequestBuilders.get(DEFAULT_URI) + .queryParams(queries)); + + // then + resultActions.andExpect(status().isOk()); + } + + @DisplayName("세션 단일 조회 성공") + @Test + void success_getLecture() throws Exception { + // given + LectureResponseDTO response = lectureResponse(); + + doReturn(response).when(lectureService).getLecture(anyLong()); + + // when + ResultActions resultActions = mockMvc.perform( + MockMvcRequestBuilders.get(DEFAULT_URI + "/{lectureId}", anyLong())); + + // then + resultActions.andExpect(status().isOk()); + } + + @DisplayName("출석 시작 성공") + @Test + void success_startAttendance() throws Exception { + // given + AttendanceRequestDTO request = attendanceRequest(); + AttendanceResponseDTO response = attendanceResponse(); + + doReturn(response).when(lectureService).startAttendance(any()); + + // when + ResultActions resultActions = mockMvc.perform( + MockMvcRequestBuilders.patch(DEFAULT_URI + "/attendance") + .contentType(MediaType.APPLICATION_JSON) + .content(new Gson().toJson(request))); + + // then + resultActions.andExpect(status().isCreated()); + } + + @DisplayName("출석 종료 성공") + @Test + void success_finishLecture() throws Exception { + // when + ResultActions resultActions = mockMvc.perform( + MockMvcRequestBuilders.patch(DEFAULT_URI + "/{lectureId}", anyLong())); + + // then + resultActions.andExpect(status().isOk()); + } + + @DisplayName("세션 삭제 성공") + @Test + void success_deleteLecture() throws Exception { + // when + ResultActions resultActions = mockMvc.perform( + MockMvcRequestBuilders.delete(DEFAULT_URI + "/{lectureId}", anyLong())); + + // then + resultActions.andExpect(status().isOk()); + } + + @DisplayName("세션 상세 조회 성공") + @Test + void success_getLectureDetail() throws Exception { + // given + LectureDetailResponseDTO response = lectureDetail(); + + doReturn(response).when(lectureService).getLectureDetail(anyLong()); + + // when + ResultActions resultActions = mockMvc.perform( + MockMvcRequestBuilders.get(DEFAULT_URI + "/detail/{lectureId}", anyLong())); + + // then + resultActions.andExpect(status().isOk()); + } + + private LectureRequestDTO lectureRequest() { + return LectureRequestDTO.builder() + .part(LECTURE_PART) + .name(LECTURE_NAME) + .generation(LECTURE_GENERATION) + .place(LECTURE_PLACE) + .startDate(NOW.toString()) + .endDate(NOW.plusHours(4).toString()) + .attribute(LECTURE_ATTRIBUTE) + .build(); + } + + private long lectureId() { + return 0L; + } + + private LecturesResponseDTO lecturesResponse() { + return new LecturesResponseDTO(LECTURE_GENERATION, lectures()); + } + + private List lectures() { + return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) + .map(this::lecture).toList(); + } + + private LectureVO lecture(int i) { + return LectureVO.builder() + .lectureId(0L) + .name(LECTURE_NAME + i) + .partValue(Part.ALL) + .partName(Part.ALL.getName()) + .startDate(NOW.plusHours(i).toString()) + .endDate(NOW.plusHours(i + 4).toString()) + .attributeValue(LECTURE_ATTRIBUTE) + .attributeName(LECTURE_ATTRIBUTE.getName()) + .place(LECTURE_PLACE + i) + .attendances(attendancesStatus()) + .build(); + } + + private LectureResponseDTO lectureResponse() { + return LectureResponseDTO.builder() + .lectureId(0L) + .name(LECTURE_NAME) + .generation(LECTURE_GENERATION) + .part(LECTURE_PART) + .attribute(LECTURE_ATTRIBUTE) + .subLectures(subLectures()) + .attendances(attendancesStatus()) + .status(LECTURE_STATUS) + .build(); + } + + private AttendancesStatusVO attendancesStatus() { + return AttendancesStatusVO.builder() + .attendance(80) + .absent(0) + .tardy(10) + .unknown(10) + .build(); + } + + private List subLectures() { + return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) + .map(this::subLecture).toList(); + } + + private SubLectureVO subLecture(int i) { + return SubLectureVO.builder() + .subLectureId((long)i) + .round(i % 2) + .startAt(NOW.toString()) + .code(SUB_LECTURE_CODE) + .build(); + } + + private AttendanceResponseDTO attendanceResponse() { + return new AttendanceResponseDTO(0L, 0L); + } + + private AttendanceRequestDTO attendanceRequest() { + return new AttendanceRequestDTO(0L, 0, SUB_LECTURE_CODE); + } + + private LectureDetailResponseDTO lectureDetail() { + return LectureDetailResponseDTO.builder() + .lectureId(0L) + .part(LECTURE_PART.getName()) + .name(LECTURE_NAME) + .place(LECTURE_PLACE) + .attribute(LECTURE_ATTRIBUTE.getName()) + .startDate(NOW.toString()) + .endDate(NOW.plusHours(4).toString()) + .generation(LECTURE_GENERATION) + .build(); + } +} \ No newline at end of file From 91700e1b08fce7e048cdd2b6d4a5fa2a8425d902 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 01:33:55 +0900 Subject: [PATCH 04/19] =?UTF-8?q?[REFACTOR]=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/MemberCustomRepository.java | 1 + .../member/MemberRepositoryImpl.java | 15 +- .../operation/service/LectureServiceImpl.java | 179 ++++++++++-------- 3 files changed, 113 insertions(+), 82 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/repository/member/MemberCustomRepository.java b/src/main/java/org/sopt/makers/operation/repository/member/MemberCustomRepository.java index 9c8c2a84..e54fd4b3 100644 --- a/src/main/java/org/sopt/makers/operation/repository/member/MemberCustomRepository.java +++ b/src/main/java/org/sopt/makers/operation/repository/member/MemberCustomRepository.java @@ -13,4 +13,5 @@ public interface MemberCustomRepository { List search(MemberSearchCondition condition); Optional find(Long memberId); int countByGenerationAndPart(int generation, Part part); + List find(int generation, Part part); } diff --git a/src/main/java/org/sopt/makers/operation/repository/member/MemberRepositoryImpl.java b/src/main/java/org/sopt/makers/operation/repository/member/MemberRepositoryImpl.java index b5259490..4bfc6858 100644 --- a/src/main/java/org/sopt/makers/operation/repository/member/MemberRepositoryImpl.java +++ b/src/main/java/org/sopt/makers/operation/repository/member/MemberRepositoryImpl.java @@ -80,7 +80,20 @@ public int countByGenerationAndPart(int generation, Part part) { .fetchFirst()); } + @Override + public List find(int generation, Part part) { + StringExpression firstName = Expressions.stringTemplate("SUBSTR({0}, 1, 1)", member.name); + + return queryFactory + .selectFrom(member) + .where( + member.generation.eq(generation), + partEq(part)) + .orderBy(firstName.asc()) + .fetch(); + } + private BooleanExpression partEq(Part part) { - return nonNull(part) ? member.part.eq(part) : null; + return (isNull(part) || part.equals(ALL)) ? null : member.part.eq(part); } } diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 6f405fde..f23bac6b 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -3,7 +3,6 @@ import static java.util.Objects.nonNull; import static org.sopt.makers.operation.common.ExceptionMessage.*; import static org.sopt.makers.operation.entity.AttendanceStatus.*; -import static org.sopt.makers.operation.entity.Part.*; import static org.sopt.makers.operation.entity.alarm.Attribute.*; import static org.sopt.makers.operation.entity.lecture.LectureStatus.*; @@ -22,7 +21,6 @@ import org.sopt.makers.operation.dto.lecture.LectureRequestDTO; import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; -import org.sopt.makers.operation.dto.member.MemberSearchCondition; import org.sopt.makers.operation.entity.*; import org.sopt.makers.operation.entity.lecture.Attribute; import org.sopt.makers.operation.entity.lecture.Lecture; @@ -55,90 +53,52 @@ public class LectureServiceImpl implements LectureService { @Value("${sopt.alarm.message.content_end}") private String ALARM_MESSAGE_CONTENT; - @Override - @Transactional - public Long createLecture(LectureRequestDTO requestDTO) { - // 세션 생성 - Lecture savedLecture = lectureRepository.save(requestDTO.toEntity()); - - // 출석 세션 2개 생성 - Stream.iterate(1, i -> i + 1).limit(2) - .forEach(i -> subLectureRepository.save(new SubLecture(savedLecture, i))); - - // 출석 생성 - memberRepository - .search(getMemberSearchCondition(requestDTO)) - .forEach(member -> attendanceRepository.save(new Attendance(member, savedLecture))); - - // 서브 출석 생성 - savedLecture.getAttendances() - .forEach(attendance -> savedLecture.getSubLectures() - .forEach(subLecture -> subAttendanceRepository.save(new SubAttendance(attendance, subLecture)))); + private final int SUB_LECTURE_MAX_ROUND = 2; + /** WEB **/ + @Override + @Transactional + public Long createLecture(LectureRequestDTO request) { + val savedLecture = saveLecture(request); + createSubLectures(savedLecture); + createAttendance(request.generation(), request.part(), savedLecture); + createSubAttendances(savedLecture); return savedLecture.getId(); } - @Override - public LectureGetResponseDTO getCurrentLecture(Long playGroundId) { - val now = LocalDateTime.now(); - - val attendances = attendanceRepository.findCurrentAttendanceByMember(playGroundId); - - if (attendances.isEmpty()) { - return new LectureGetResponseDTO(LectureResponseType.NO_SESSION, 0L, "", "", "", "", "", Collections.emptyList()); - } - - if (attendances.size() > 2) { - throw new LectureException(INVALID_COUNT_SESSION.getName()); - } - - // 현재 출석과 Lecture 가져오기 - val currentAttendance = getCurrentAttendance(attendances, now); - val currentLecture = currentAttendance.getLecture(); - val lectureType = getLectureResponseType(currentLecture); - - if (lectureType.equals(LectureResponseType.NO_ATTENDANCE)) { - val message = "출석 점수가 반영되지 않아요."; - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); - } - - val subAttendances = attendanceRepository.findSubAttendanceByAttendanceId(currentAttendance.getId()); - - val firstSubLectureAttendance = subAttendances.get(0); - val secondSubLectureAttendance = subAttendances.get(1); + private Lecture saveLecture(LectureRequestDTO request) { + val lecture = request.toEntity(); + return lectureRepository.save(lecture); + } - val firstSubLectureAttendanceStatus = firstSubLectureAttendance.getStatus(); - val secondSubLectureAttendanceStatus = secondSubLectureAttendance.getStatus(); + private void createSubLectures(Lecture lecture) { + Stream.iterate(1, i -> i + 1).limit(SUB_LECTURE_MAX_ROUND) + .forEach(round -> saveSubLecture(lecture, round)); + } - val firstSessionStart = firstSubLectureAttendance.getSubLecture().getStartAt(); - val secondSessionStart = secondSubLectureAttendance.getSubLecture().getStartAt(); + private void saveSubLecture(Lecture lecture, int round) { + subLectureRepository.save(new SubLecture(lecture, round)); + } - val message = (currentLecture.getAttribute() == Attribute.SEMINAR) ? "" : "행사도 참여하고, 출석점수도 받고, 일석이조!"; + private void createAttendance(int generation, Part part, Lecture lecture) { + memberRepository.find(generation, part).forEach(member -> saveAttendance(member, lecture)); + } - // Lecture 시작 전 혹은 1차 출석 시작 전 - if (now.isBefore(currentLecture.getStartDate()) || !nonNull(firstSessionStart)) { - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); - } + private void saveAttendance(Member member, Lecture lecture) { + attendanceRepository.save(new Attendance(member, lecture)); + } - // 1차 출석 시작, 2차 출석 시작 전 - if (now.isAfter(firstSessionStart) && !nonNull(secondSessionStart)) { - // 1차 출석 중 결석인 상태 - if (now.isBefore(firstSessionStart.plusMinutes(10)) && firstSubLectureAttendanceStatus.equals(ABSENT)) { - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); - } + private void createSubAttendances(Lecture lecture) { + lecture.getAttendances().forEach(this::saveSubAttendances); + } - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.singletonList(firstSubLectureAttendance)); - } + private void saveSubAttendances(Attendance attendance) { + attendance.getLecture().getSubLectures().forEach(subLecture -> saveSubAttendance(attendance, subLecture)); + } - // 2차 출석 시작 이후 - if (now.isAfter(secondSessionStart)) { - // 2차 출석 중 결석인 상태 - if (now.isBefore(secondSessionStart.plusMinutes(10)) && secondSubLectureAttendanceStatus.equals(ABSENT)) { - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.singletonList(firstSubLectureAttendance)); - } - } - return LectureGetResponseDTO.of(lectureType, currentLecture, message, subAttendances); + private void saveSubAttendance(Attendance attendance, SubLecture subLecture) { + subAttendanceRepository.save(new SubAttendance(attendance, subLecture)); } @Override @@ -194,6 +154,8 @@ public void finishLecture(Long lectureId) { alarmSender.send(new AlarmSenderDTO(alarmTitle, ALARM_MESSAGE_CONTENT, memberPgIds, NEWS, null)); } + /** APP **/ + @Override @Transactional public void finishLecture() { @@ -215,6 +177,68 @@ public void finishLecture() { } } + @Override + public LectureGetResponseDTO getCurrentLecture(Long playGroundId) { + val now = LocalDateTime.now(); + + val attendances = attendanceRepository.findCurrentAttendanceByMember(playGroundId); + + if (attendances.isEmpty()) { + return new LectureGetResponseDTO(LectureResponseType.NO_SESSION, 0L, "", "", "", "", "", Collections.emptyList()); + } + + if (attendances.size() > 2) { + throw new LectureException(INVALID_COUNT_SESSION.getName()); + } + + // 현재 출석과 Lecture 가져오기 + val currentAttendance = getCurrentAttendance(attendances, now); + val currentLecture = currentAttendance.getLecture(); + val lectureType = getLectureResponseType(currentLecture); + + if (lectureType.equals(LectureResponseType.NO_ATTENDANCE)) { + val message = "출석 점수가 반영되지 않아요."; + return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); + } + + val subAttendances = attendanceRepository.findSubAttendanceByAttendanceId(currentAttendance.getId()); + + val firstSubLectureAttendance = subAttendances.get(0); + val secondSubLectureAttendance = subAttendances.get(1); + + val firstSubLectureAttendanceStatus = firstSubLectureAttendance.getStatus(); + val secondSubLectureAttendanceStatus = secondSubLectureAttendance.getStatus(); + + val firstSessionStart = firstSubLectureAttendance.getSubLecture().getStartAt(); + val secondSessionStart = secondSubLectureAttendance.getSubLecture().getStartAt(); + + val message = (currentLecture.getAttribute() == Attribute.SEMINAR) ? "" : "행사도 참여하고, 출석점수도 받고, 일석이조!"; + + // Lecture 시작 전 혹은 1차 출석 시작 전 + if (now.isBefore(currentLecture.getStartDate()) || !nonNull(firstSessionStart)) { + return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); + } + + // 1차 출석 시작, 2차 출석 시작 전 + if (now.isAfter(firstSessionStart) && !nonNull(secondSessionStart)) { + // 1차 출석 중 결석인 상태 + if (now.isBefore(firstSessionStart.plusMinutes(10)) && firstSubLectureAttendanceStatus.equals(ABSENT)) { + return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); + } + + return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.singletonList(firstSubLectureAttendance)); + } + + // 2차 출석 시작 이후 + if (now.isAfter(secondSessionStart)) { + // 2차 출석 중 결석인 상태 + if (now.isBefore(secondSessionStart.plusMinutes(10)) && secondSubLectureAttendanceStatus.equals(ABSENT)) { + return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.singletonList(firstSubLectureAttendance)); + } + } + return LectureGetResponseDTO.of(lectureType, currentLecture, message, subAttendances); + } + @Override public LectureCurrentRoundResponseDTO getCurrentLectureRound(Long lectureId) { val now = LocalDateTime.now(); @@ -288,13 +312,6 @@ public LectureDetailResponseDTO getLectureDetail(Long lectureId) { return LectureDetailResponseDTO.of(lecture); } - private MemberSearchCondition getMemberSearchCondition(LectureRequestDTO requestDTO) { - return new MemberSearchCondition( - !requestDTO.part().equals(ALL) ? requestDTO.part() : null, - requestDTO.generation() - ); - } - private Lecture findLecture(Long id) { return lectureRepository.findById(id) .orElseThrow(() -> new LectureException(INVALID_LECTURE.getName())); From de15bd5890a1144e93ef791ac718616e02a33d6d Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 01:34:33 +0900 Subject: [PATCH 05/19] =?UTF-8?q?[REFACTOR]=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/sopt/makers/operation/service/LectureService.java | 2 +- .../org/sopt/makers/operation/service/LectureServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/service/LectureService.java b/src/main/java/org/sopt/makers/operation/service/LectureService.java index 910aadc1..04e033a3 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureService.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureService.java @@ -10,7 +10,7 @@ import org.sopt.makers.operation.dto.lecture.*; public interface LectureService { - Long createLecture(LectureRequestDTO requestDTO); + long createLecture(LectureRequestDTO requestDTO); LectureGetResponseDTO getCurrentLecture(Long playGroundId); LecturesResponseDTO getLecturesByGeneration(int generation, Part part); LectureResponseDTO getLecture(Long lectureId); diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index f23bac6b..3beadafe 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -59,7 +59,7 @@ public class LectureServiceImpl implements LectureService { @Override @Transactional - public Long createLecture(LectureRequestDTO request) { + public long createLecture(LectureRequestDTO request) { val savedLecture = saveLecture(request); createSubLectures(savedLecture); createAttendance(request.generation(), request.part(), savedLecture); From f4df0630df46c780478e26ea8f2f5deb6dae7442 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 10:55:37 +0900 Subject: [PATCH 06/19] =?UTF-8?q?[REFACTOR]=20Value=20=EA=B0=92=20?= =?UTF-8?q?=ED=95=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=82=B4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../makers/operation/config/ValueConfig.java | 17 ++++++++++++++++ .../operation/service/LectureServiceImpl.java | 20 +++++++------------ 2 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/sopt/makers/operation/config/ValueConfig.java diff --git a/src/main/java/org/sopt/makers/operation/config/ValueConfig.java b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java new file mode 100644 index 00000000..a94b0438 --- /dev/null +++ b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java @@ -0,0 +1,17 @@ +package org.sopt.makers.operation.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import lombok.Getter; + +@Configuration +@Getter +public class ValueConfig { + @Value("${sopt.alarm.message.title_end}") + private String ALARM_MESSAGE_TITLE; + @Value("${sopt.alarm.message.content_end}") + private String ALARM_MESSAGE_CONTENT; + + private final int SUB_LECTURE_MAX_ROUND = 2; +} diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 3beadafe..6b09b1ec 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -13,6 +13,7 @@ import lombok.val; +import org.sopt.makers.operation.config.ValueConfig; import org.sopt.makers.operation.dto.alarm.AlarmSenderDTO; import org.sopt.makers.operation.dto.lecture.*; @@ -31,7 +32,6 @@ import org.sopt.makers.operation.repository.lecture.LectureRepository; import org.sopt.makers.operation.repository.lecture.SubLectureRepository; import org.sopt.makers.operation.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -47,13 +47,7 @@ public class LectureServiceImpl implements LectureService { private final SubAttendanceRepository subAttendanceRepository; private final MemberRepository memberRepository; private final AlarmSender alarmSender; - - @Value("${sopt.alarm.message.title_end}") - private String ALARM_MESSAGE_TITLE; - @Value("${sopt.alarm.message.content_end}") - private String ALARM_MESSAGE_CONTENT; - - private final int SUB_LECTURE_MAX_ROUND = 2; + private final ValueConfig valueConfig; /** WEB **/ @@ -73,7 +67,7 @@ private Lecture saveLecture(LectureRequestDTO request) { } private void createSubLectures(Lecture lecture) { - Stream.iterate(1, i -> i + 1).limit(SUB_LECTURE_MAX_ROUND) + Stream.iterate(1, i -> i + 1).limit(valueConfig.getSUB_LECTURE_MAX_ROUND()) .forEach(round -> saveSubLecture(lecture, round)); } @@ -150,8 +144,8 @@ public void finishLecture(Long lectureId) { .filter(id -> !id.equals("null")) .toList(); - val alarmTitle = lecture.getName() + " " + ALARM_MESSAGE_TITLE; - alarmSender.send(new AlarmSenderDTO(alarmTitle, ALARM_MESSAGE_CONTENT, memberPgIds, NEWS, null)); + val alarmTitle = lecture.getName() + " " + valueConfig.getALARM_MESSAGE_TITLE(); + alarmSender.send(new AlarmSenderDTO(alarmTitle, valueConfig.getALARM_MESSAGE_CONTENT(), memberPgIds, NEWS, null)); } /** APP **/ @@ -172,8 +166,8 @@ public void finishLecture() { } } - val alarmTitle = lecture.getName() + " " + ALARM_MESSAGE_TITLE; - alarmSender.send(new AlarmSenderDTO(alarmTitle, ALARM_MESSAGE_CONTENT, memberPgIds, NEWS, null)); + val alarmTitle = lecture.getName() + " " + valueConfig.getALARM_MESSAGE_TITLE(); + alarmSender.send(new AlarmSenderDTO(alarmTitle, valueConfig.getALARM_MESSAGE_CONTENT(), memberPgIds, NEWS, null)); } } From 1f21149e59efbc87859f7b41b40d7769847fcfb2 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 10:57:00 +0900 Subject: [PATCH 07/19] =?UTF-8?q?[REFACTOR]=20=ED=95=9C=20=EC=A4=84=20?= =?UTF-8?q?=EB=9D=84=EC=9A=B0=EA=B3=A0=20=EC=8B=9C=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sopt/makers/operation/config/ValueConfig.java | 1 + .../makers/operation/service/LectureService.java | 1 + .../operation/service/LectureServiceImpl.java | 1 + .../operation/service/LectureServiceImplTest.java | 13 +++++++++++++ 4 files changed, 16 insertions(+) create mode 100644 src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java diff --git a/src/main/java/org/sopt/makers/operation/config/ValueConfig.java b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java index a94b0438..9c36a59e 100644 --- a/src/main/java/org/sopt/makers/operation/config/ValueConfig.java +++ b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java @@ -8,6 +8,7 @@ @Configuration @Getter public class ValueConfig { + @Value("${sopt.alarm.message.title_end}") private String ALARM_MESSAGE_TITLE; @Value("${sopt.alarm.message.content_end}") diff --git a/src/main/java/org/sopt/makers/operation/service/LectureService.java b/src/main/java/org/sopt/makers/operation/service/LectureService.java index 04e033a3..f74532e7 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureService.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureService.java @@ -10,6 +10,7 @@ import org.sopt.makers.operation.dto.lecture.*; public interface LectureService { + long createLecture(LectureRequestDTO requestDTO); LectureGetResponseDTO getCurrentLecture(Long playGroundId); LecturesResponseDTO getLecturesByGeneration(int generation, Part part); diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 6b09b1ec..831b0770 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -41,6 +41,7 @@ @RequiredArgsConstructor @Transactional(readOnly = true) public class LectureServiceImpl implements LectureService { + private final LectureRepository lectureRepository; private final SubLectureRepository subLectureRepository; private final AttendanceRepository attendanceRepository; diff --git a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java new file mode 100644 index 00000000..1085bfe4 --- /dev/null +++ b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java @@ -0,0 +1,13 @@ +package org.sopt.makers.operation.service; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class LectureServiceImplTest { + + @InjectMocks +} \ No newline at end of file From bbe6a4200fddaa4acfb62617bd47604a71cae856 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 11:05:43 +0900 Subject: [PATCH 08/19] =?UTF-8?q?[TEST]=20=EC=84=B8=EC=85=98=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/LectureControllerTest.java | 105 +----------------- 1 file changed, 1 insertion(+), 104 deletions(-) diff --git a/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java b/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java index bf22b432..0197a2d4 100644 --- a/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java +++ b/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java @@ -1,9 +1,5 @@ package org.sopt.makers.operation.controller.web; -import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Stream; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,16 +9,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.sopt.makers.operation.dto.lecture.AttendanceRequestDTO; import org.sopt.makers.operation.dto.lecture.AttendanceResponseDTO; -import org.sopt.makers.operation.dto.lecture.AttendancesStatusVO; import org.sopt.makers.operation.dto.lecture.LectureDetailResponseDTO; import org.sopt.makers.operation.dto.lecture.LectureRequestDTO; import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; -import org.sopt.makers.operation.dto.lecture.LectureResponseDTO.SubLectureVO; import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; -import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO.LectureVO; -import org.sopt.makers.operation.entity.Part; -import org.sopt.makers.operation.entity.lecture.Attribute; -import org.sopt.makers.operation.entity.lecture.LectureStatus; import org.sopt.makers.operation.service.LectureService; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; @@ -33,6 +23,7 @@ import org.springframework.util.MultiValueMap; import static org.mockito.Mockito.*; +import static org.sopt.makers.operation.fixture.LectureFixture.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import com.google.gson.Gson; @@ -48,15 +39,6 @@ class LectureControllerTest { private MockMvc mockMvc; private final String DEFAULT_URI = "/api/v1/lectures"; - private final String LECTURE_NAME = "테스트 이름"; - private final Part LECTURE_PART = Part.ALL; - private final int LECTURE_GENERATION = 30; - private final String LECTURE_PLACE = "테스트 장소"; - private final LocalDateTime NOW = LocalDateTime.now(); - private final Attribute LECTURE_ATTRIBUTE = Attribute.ETC; - private final LectureStatus LECTURE_STATUS = LectureStatus.BEFORE; - private final int LIST_SIZE = 5; - private final String SUB_LECTURE_CODE = "code"; @BeforeEach public void init() { @@ -185,89 +167,4 @@ private LectureRequestDTO lectureRequest() { .attribute(LECTURE_ATTRIBUTE) .build(); } - - private long lectureId() { - return 0L; - } - - private LecturesResponseDTO lecturesResponse() { - return new LecturesResponseDTO(LECTURE_GENERATION, lectures()); - } - - private List lectures() { - return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) - .map(this::lecture).toList(); - } - - private LectureVO lecture(int i) { - return LectureVO.builder() - .lectureId(0L) - .name(LECTURE_NAME + i) - .partValue(Part.ALL) - .partName(Part.ALL.getName()) - .startDate(NOW.plusHours(i).toString()) - .endDate(NOW.plusHours(i + 4).toString()) - .attributeValue(LECTURE_ATTRIBUTE) - .attributeName(LECTURE_ATTRIBUTE.getName()) - .place(LECTURE_PLACE + i) - .attendances(attendancesStatus()) - .build(); - } - - private LectureResponseDTO lectureResponse() { - return LectureResponseDTO.builder() - .lectureId(0L) - .name(LECTURE_NAME) - .generation(LECTURE_GENERATION) - .part(LECTURE_PART) - .attribute(LECTURE_ATTRIBUTE) - .subLectures(subLectures()) - .attendances(attendancesStatus()) - .status(LECTURE_STATUS) - .build(); - } - - private AttendancesStatusVO attendancesStatus() { - return AttendancesStatusVO.builder() - .attendance(80) - .absent(0) - .tardy(10) - .unknown(10) - .build(); - } - - private List subLectures() { - return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) - .map(this::subLecture).toList(); - } - - private SubLectureVO subLecture(int i) { - return SubLectureVO.builder() - .subLectureId((long)i) - .round(i % 2) - .startAt(NOW.toString()) - .code(SUB_LECTURE_CODE) - .build(); - } - - private AttendanceResponseDTO attendanceResponse() { - return new AttendanceResponseDTO(0L, 0L); - } - - private AttendanceRequestDTO attendanceRequest() { - return new AttendanceRequestDTO(0L, 0, SUB_LECTURE_CODE); - } - - private LectureDetailResponseDTO lectureDetail() { - return LectureDetailResponseDTO.builder() - .lectureId(0L) - .part(LECTURE_PART.getName()) - .name(LECTURE_NAME) - .place(LECTURE_PLACE) - .attribute(LECTURE_ATTRIBUTE.getName()) - .startDate(NOW.toString()) - .endDate(NOW.plusHours(4).toString()) - .generation(LECTURE_GENERATION) - .build(); - } } \ No newline at end of file From 45692df9b5fef9962ffa25e2bdbf2334ab33f2df Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 11:05:49 +0900 Subject: [PATCH 09/19] =?UTF-8?q?[TEST]=20=EC=84=B8=EC=85=98=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../operation/fixture/LectureFixture.java | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java diff --git a/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java new file mode 100644 index 00000000..91ca8cd8 --- /dev/null +++ b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java @@ -0,0 +1,113 @@ +package org.sopt.makers.operation.fixture; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Stream; + +import org.sopt.makers.operation.dto.lecture.AttendanceRequestDTO; +import org.sopt.makers.operation.dto.lecture.AttendanceResponseDTO; +import org.sopt.makers.operation.dto.lecture.AttendancesStatusVO; +import org.sopt.makers.operation.dto.lecture.LectureDetailResponseDTO; +import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; +import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; +import org.sopt.makers.operation.entity.Part; +import org.sopt.makers.operation.entity.lecture.Attribute; +import org.sopt.makers.operation.entity.lecture.LectureStatus; + +public class LectureFixture { + + public static final String LECTURE_NAME = "테스트 이름"; + public static final Part LECTURE_PART = Part.ALL; + public static final int LECTURE_GENERATION = 30; + public static final String LECTURE_PLACE = "테스트 장소"; + public static final LocalDateTime NOW = LocalDateTime.now(); + public static final Attribute LECTURE_ATTRIBUTE = Attribute.ETC; + public static final LectureStatus LECTURE_STATUS = LectureStatus.BEFORE; + public static final int LIST_SIZE = 5; + public static final String SUB_LECTURE_CODE = "code"; + + public static long lectureId() { + return 0L; + } + + public static LecturesResponseDTO lecturesResponse() { + return new LecturesResponseDTO(LECTURE_GENERATION, lectures()); + } + + private static List lectures() { + return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) + .map(LectureFixture::lecture).toList(); + } + + private static LecturesResponseDTO.LectureVO lecture(int i) { + return LecturesResponseDTO.LectureVO.builder() + .lectureId(0L) + .name(LECTURE_NAME + i) + .partValue(Part.ALL) + .partName(Part.ALL.getName()) + .startDate(NOW.plusHours(i).toString()) + .endDate(NOW.plusHours(i + 4).toString()) + .attributeValue(LECTURE_ATTRIBUTE) + .attributeName(LECTURE_ATTRIBUTE.getName()) + .place(LECTURE_PLACE + i) + .attendances(attendancesStatus()) + .build(); + } + + public static LectureResponseDTO lectureResponse() { + return LectureResponseDTO.builder() + .lectureId(0L) + .name(LECTURE_NAME) + .generation(LECTURE_GENERATION) + .part(LECTURE_PART) + .attribute(LECTURE_ATTRIBUTE) + .subLectures(subLectures()) + .attendances(attendancesStatus()) + .status(LECTURE_STATUS) + .build(); + } + + private static AttendancesStatusVO attendancesStatus() { + return AttendancesStatusVO.builder() + .attendance(80) + .absent(0) + .tardy(10) + .unknown(10) + .build(); + } + + private static List subLectures() { + return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) + .map(LectureFixture::subLecture).toList(); + } + + private static LectureResponseDTO.SubLectureVO subLecture(int i) { + return LectureResponseDTO.SubLectureVO.builder() + .subLectureId((long)i) + .round(i % 2) + .startAt(NOW.toString()) + .code(SUB_LECTURE_CODE) + .build(); + } + + public static AttendanceResponseDTO attendanceResponse() { + return new AttendanceResponseDTO(0L, 0L); + } + + public static AttendanceRequestDTO attendanceRequest() { + return new AttendanceRequestDTO(0L, 0, SUB_LECTURE_CODE); + } + + public static LectureDetailResponseDTO lectureDetail() { + return LectureDetailResponseDTO.builder() + .lectureId(0L) + .part(LECTURE_PART.getName()) + .name(LECTURE_NAME) + .place(LECTURE_PLACE) + .attribute(LECTURE_ATTRIBUTE.getName()) + .startDate(NOW.toString()) + .endDate(NOW.plusHours(4).toString()) + .generation(LECTURE_GENERATION) + .build(); + } +} From 12ad5e5de398cacc96fd5597dc6d9b9b84aa9e6f Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 12:16:13 +0900 Subject: [PATCH 10/19] =?UTF-8?q?[REFACTOR]=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/LectureController.java | 4 +-- .../lecture/LectureCustomRepository.java | 2 +- .../lecture/LectureRepositoryImpl.java | 2 +- .../operation/service/LectureService.java | 2 +- .../operation/service/LectureServiceImpl.java | 4 +-- .../controller/web/LectureControllerTest.java | 15 ++------- .../operation/fixture/LectureFixture.java | 33 +++++++++++++++---- 7 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java b/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java index 43d57790..9cc4e264 100644 --- a/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java +++ b/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java @@ -45,8 +45,8 @@ public ResponseEntity createLecture(@RequestBody LectureRequestDTO @ApiOperation(value = "세션 리스트 조회") @GetMapping - public ResponseEntity getLecturesByGeneration(@RequestParam int generation, @RequestParam(required = false) Part part) { - val response = lectureService.getLecturesByGeneration(generation, part); + public ResponseEntity getLectures(@RequestParam int generation, @RequestParam(required = false) Part part) { + val response = lectureService.getLectures(generation, part); return ResponseEntity.ok(success(SUCCESS_GET_LECTURES.getMessage(), response)); } diff --git a/src/main/java/org/sopt/makers/operation/repository/lecture/LectureCustomRepository.java b/src/main/java/org/sopt/makers/operation/repository/lecture/LectureCustomRepository.java index b17ca536..64bf58ae 100644 --- a/src/main/java/org/sopt/makers/operation/repository/lecture/LectureCustomRepository.java +++ b/src/main/java/org/sopt/makers/operation/repository/lecture/LectureCustomRepository.java @@ -6,7 +6,7 @@ import java.util.Optional; public interface LectureCustomRepository { - List findLectures(int generation, Part part); + List find(int generation, Part part); List findLecturesToBeEnd(); Optional find(Long lectureId); } diff --git a/src/main/java/org/sopt/makers/operation/repository/lecture/LectureRepositoryImpl.java b/src/main/java/org/sopt/makers/operation/repository/lecture/LectureRepositoryImpl.java index 85772ee1..51960170 100644 --- a/src/main/java/org/sopt/makers/operation/repository/lecture/LectureRepositoryImpl.java +++ b/src/main/java/org/sopt/makers/operation/repository/lecture/LectureRepositoryImpl.java @@ -22,7 +22,7 @@ public class LectureRepositoryImpl implements LectureCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findLectures(int generation, Part part) { + public List find(int generation, Part part) { return queryFactory .selectFrom(lecture) .leftJoin(lecture.attendances, attendance).fetchJoin().distinct() diff --git a/src/main/java/org/sopt/makers/operation/service/LectureService.java b/src/main/java/org/sopt/makers/operation/service/LectureService.java index f74532e7..6a16ee0c 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureService.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureService.java @@ -12,8 +12,8 @@ public interface LectureService { long createLecture(LectureRequestDTO requestDTO); + LecturesResponseDTO getLectures(int generation, Part part); LectureGetResponseDTO getCurrentLecture(Long playGroundId); - LecturesResponseDTO getLecturesByGeneration(int generation, Part part); LectureResponseDTO getLecture(Long lectureId); AttendanceResponseDTO startAttendance(AttendanceRequestDTO requestDTO); void finishLecture(Long lectureId); diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 831b0770..330f2f16 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -97,8 +97,8 @@ private void saveSubAttendance(Attendance attendance, SubLecture subLecture) { } @Override - public LecturesResponseDTO getLecturesByGeneration(int generation, Part part) { - val lectures = lectureRepository.findLectures(generation, part); + public LecturesResponseDTO getLectures(int generation, Part part) { + val lectures = lectureRepository.find(generation, part); return LecturesResponseDTO.of(generation, lectures); } diff --git a/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java b/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java index 0197a2d4..f00c2aa4 100644 --- a/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java +++ b/src/test/java/org/sopt/makers/operation/controller/web/LectureControllerTest.java @@ -30,6 +30,7 @@ @ExtendWith(MockitoExtension.class) class LectureControllerTest { + @InjectMocks private LectureController lectureController; @@ -72,7 +73,7 @@ void success_getLectureList() throws Exception { MultiValueMap queries = new LinkedMultiValueMap<>(); queries.add("generation", String.valueOf(LECTURE_GENERATION)); - doReturn(response).when(lectureService).getLecturesByGeneration(anyInt(), any()); + doReturn(response).when(lectureService).getLectures(anyInt(), any()); // when ResultActions resultActions = mockMvc.perform( @@ -155,16 +156,4 @@ void success_getLectureDetail() throws Exception { // then resultActions.andExpect(status().isOk()); } - - private LectureRequestDTO lectureRequest() { - return LectureRequestDTO.builder() - .part(LECTURE_PART) - .name(LECTURE_NAME) - .generation(LECTURE_GENERATION) - .place(LECTURE_PLACE) - .startDate(NOW.toString()) - .endDate(NOW.plusHours(4).toString()) - .attribute(LECTURE_ATTRIBUTE) - .build(); - } } \ No newline at end of file diff --git a/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java index 91ca8cd8..a11a6932 100644 --- a/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java +++ b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java @@ -8,10 +8,14 @@ import org.sopt.makers.operation.dto.lecture.AttendanceResponseDTO; import org.sopt.makers.operation.dto.lecture.AttendancesStatusVO; import org.sopt.makers.operation.dto.lecture.LectureDetailResponseDTO; +import org.sopt.makers.operation.dto.lecture.LectureRequestDTO; import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; +import org.sopt.makers.operation.dto.lecture.LectureResponseDTO.SubLectureVO; import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; +import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO.LectureVO; import org.sopt.makers.operation.entity.Part; import org.sopt.makers.operation.entity.lecture.Attribute; +import org.sopt.makers.operation.entity.lecture.Lecture; import org.sopt.makers.operation.entity.lecture.LectureStatus; public class LectureFixture { @@ -26,6 +30,18 @@ public class LectureFixture { public static final int LIST_SIZE = 5; public static final String SUB_LECTURE_CODE = "code"; + public static LectureRequestDTO lectureRequest() { + return LectureRequestDTO.builder() + .part(LECTURE_PART) + .name(LECTURE_NAME) + .generation(LECTURE_GENERATION) + .place(LECTURE_PLACE) + .startDate(NOW.toString()) + .endDate(NOW.plusHours(4).toString()) + .attribute(LECTURE_ATTRIBUTE) + .build(); + } + public static long lectureId() { return 0L; } @@ -34,13 +50,13 @@ public static LecturesResponseDTO lecturesResponse() { return new LecturesResponseDTO(LECTURE_GENERATION, lectures()); } - private static List lectures() { + private static List lectures() { return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) .map(LectureFixture::lecture).toList(); } - private static LecturesResponseDTO.LectureVO lecture(int i) { - return LecturesResponseDTO.LectureVO.builder() + private static LectureVO lecture(int i) { + return LectureVO.builder() .lectureId(0L) .name(LECTURE_NAME + i) .partValue(Part.ALL) @@ -76,13 +92,13 @@ private static AttendancesStatusVO attendancesStatus() { .build(); } - private static List subLectures() { + private static List subLectures() { return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) .map(LectureFixture::subLecture).toList(); } - private static LectureResponseDTO.SubLectureVO subLecture(int i) { - return LectureResponseDTO.SubLectureVO.builder() + private static SubLectureVO subLecture(int i) { + return SubLectureVO.builder() .subLectureId((long)i) .round(i % 2) .startAt(NOW.toString()) @@ -110,4 +126,9 @@ public static LectureDetailResponseDTO lectureDetail() { .generation(LECTURE_GENERATION) .build(); } + + public static List lectureList() { + return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) + .map(i -> lectureRequest().toEntity()).toList(); + } } From 49e7558dcea926c5d0f7d3a60fbb37ac016cd3f9 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 12:16:33 +0900 Subject: [PATCH 11/19] =?UTF-8?q?[TEST]=20=EC=84=B8=EC=85=98=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/LectureServiceImplTest.java | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java index 1085bfe4..a1491be7 100644 --- a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java +++ b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java @@ -1,13 +1,48 @@ package org.sopt.makers.operation.service; -import static org.junit.jupiter.api.Assertions.*; +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; +import static org.sopt.makers.operation.fixture.LectureFixture.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.sopt.makers.operation.config.ValueConfig; +import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; +import org.sopt.makers.operation.repository.lecture.LectureRepository; +import org.sopt.makers.operation.repository.member.MemberRepository; + +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class LectureServiceImplTest { @InjectMocks + LectureServiceImpl lectureService; + + @Mock + private LectureRepository lectureRepository; + @Mock + private MemberRepository memberRepository; + @Mock + ValueConfig valueConfig; + + @DisplayName("세션 목록 조회") + @Test + void getLectures() { + // given + doReturn(lectureList()).when(lectureRepository).find(anyInt(), any()); + + // when + LecturesResponseDTO response = lectureService.getLectures(LECTURE_GENERATION, LECTURE_PART); + + // then + assertThat(response.lectures().size(), is(equalTo(LIST_SIZE))); + + // verify + verify(lectureRepository, times(1)).find(anyInt(), any()); + } } \ No newline at end of file From f58055cb34bb88bf23b2df5dbb714962c2e4745f Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 12:23:32 +0900 Subject: [PATCH 12/19] =?UTF-8?q?[TEST]=20=EC=84=B8=EC=85=98=20=EB=8B=A8?= =?UTF-8?q?=EA=B1=B4=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/LectureServiceImplTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java index a1491be7..ef093a9d 100644 --- a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java +++ b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java @@ -11,12 +11,16 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.sopt.makers.operation.config.ValueConfig; +import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; +import org.sopt.makers.operation.entity.lecture.Lecture; import org.sopt.makers.operation.repository.lecture.LectureRepository; import org.sopt.makers.operation.repository.member.MemberRepository; import static org.mockito.Mockito.*; +import java.util.Optional; + @ExtendWith(MockitoExtension.class) class LectureServiceImplTest { @@ -45,4 +49,26 @@ void getLectures() { // verify verify(lectureRepository, times(1)).find(anyInt(), any()); } + + @DisplayName("세션 단건 조회") + @Test + void getLecture() { + // given + Lecture lecture = lectureRequest().toEntity(); + long lectureId = lectureId(); + + doReturn(Optional.of(lecture)).when(lectureRepository).findById(anyLong()); + + // when + LectureResponseDTO response = lectureService.getLecture(lectureId); + + // then + assertThat(response.name(), is(equalTo(lecture.getName()))); + assertThat(response.generation(), is(equalTo(lecture.getGeneration()))); + assertThat(response.part(), is(equalTo(lecture.getPart()))); + assertThat(response.attribute(), is(equalTo(lecture.getAttribute()))); + + // verify + verify(lectureRepository, times(1)).findById(anyLong()); + } } \ No newline at end of file From 75abd9591c5ab0e8b20ed9694e632e0e9703b337 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 12:41:45 +0900 Subject: [PATCH 13/19] =?UTF-8?q?[REFACTOR]=20=EC=B6=9C=EC=84=9D=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/lecture/AttendanceResponseDTO.java | 7 ++++ .../operation/entity/lecture/Lecture.java | 8 +++++ .../operation/service/LectureServiceImpl.java | 32 +++++++++++-------- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java b/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java index da99b041..ed025359 100644 --- a/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java +++ b/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java @@ -1,7 +1,14 @@ package org.sopt.makers.operation.dto.lecture; +import org.sopt.makers.operation.entity.SubLecture; +import org.sopt.makers.operation.entity.lecture.Lecture; + public record AttendanceResponseDTO( Long lectureId, Long subLectureId ) { + + public static AttendanceResponseDTO of(Lecture lecture, SubLecture subLecture) { + return new AttendanceResponseDTO(lecture.getId(), subLecture.getId()); + } } diff --git a/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java b/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java index 29201733..5027ce8f 100644 --- a/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java +++ b/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java @@ -78,4 +78,12 @@ public void finish() { this.lectureStatus = LectureStatus.END; attendances.forEach(Attendance::updateMemberScore); } + + public boolean isEnd() { + return this.lectureStatus.equals(LectureStatus.END); + } + + public boolean isBefore() { + return this.lectureStatus.equals(LectureStatus.BEFORE); + } } diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 330f2f16..2571d36f 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -26,6 +26,7 @@ import org.sopt.makers.operation.entity.lecture.Attribute; import org.sopt.makers.operation.entity.lecture.Lecture; import org.sopt.makers.operation.exception.LectureException; +import org.sopt.makers.operation.exception.SubLectureException; import org.sopt.makers.operation.external.api.AlarmSender; import org.sopt.makers.operation.repository.attendance.AttendanceRepository; import org.sopt.makers.operation.repository.SubAttendanceRepository; @@ -111,23 +112,26 @@ public LectureResponseDTO getLecture(Long lectureId) { @Override @Transactional public AttendanceResponseDTO startAttendance(AttendanceRequestDTO requestDTO) { - Lecture lecture = findLecture(requestDTO.lectureId()); + val lecture = findLecture(requestDTO.lectureId()); + checkValidAttendance(lecture, requestDTO.round()); + val subLecture = getSubLecture(lecture, requestDTO.round()); + subLecture.startAttendance(requestDTO.code()); + return AttendanceResponseDTO.of(lecture, subLecture); + } - // 출석 가능 여부 유효성 체크 - if (requestDTO.round() == 2 && lecture.getLectureStatus().equals(BEFORE)) { - throw new IllegalStateException(NOT_STARTED_PRE_ATTENDANCE.getName()); - } else if (lecture.getLectureStatus().equals(END)) { - throw new IllegalStateException(END_LECTURE.getName()); + private void checkValidAttendance(Lecture lecture, int round) { + if (lecture.isEnd()) { + throw new LectureException(END_LECTURE.getName()); + } else if (round == 2 && lecture.isBefore()) { + throw new LectureException(NOT_STARTED_PRE_ATTENDANCE.getName()); } + } - // 출석 세션 상태 업데이트 (시작) - SubLecture subLecture = lecture.getSubLectures().stream() - .filter(session -> session.getRound() == requestDTO.round()) - .findFirst() - .orElseThrow(() -> new IllegalStateException(NO_SUB_LECTURE_EQUAL_ROUND.getName())); - subLecture.startAttendance(requestDTO.code()); - - return new AttendanceResponseDTO(lecture.getId(), subLecture.getId()); + private SubLecture getSubLecture(Lecture lecture, int round) { + return lecture.getSubLectures().stream() + .filter(l -> l.getRound() == round) + .findFirst() + .orElseThrow(() -> new SubLectureException(NO_SUB_LECTURE_EQUAL_ROUND.getName())); } @Override From eb6b1ea9f1958aaace53d56edb7cea9fc144cf05 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 12:54:40 +0900 Subject: [PATCH 14/19] =?UTF-8?q?[TEST]=20=EC=B6=9C=EC=84=9D=20=EC=8B=9C?= =?UTF-8?q?=EC=9E=91=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../operation/fixture/LectureFixture.java | 7 ++++++- .../service/LectureServiceImplTest.java | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java index a11a6932..898bf7d1 100644 --- a/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java +++ b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java @@ -14,6 +14,7 @@ import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO.LectureVO; import org.sopt.makers.operation.entity.Part; +import org.sopt.makers.operation.entity.SubLecture; import org.sopt.makers.operation.entity.lecture.Attribute; import org.sopt.makers.operation.entity.lecture.Lecture; import org.sopt.makers.operation.entity.lecture.LectureStatus; @@ -111,7 +112,7 @@ public static AttendanceResponseDTO attendanceResponse() { } public static AttendanceRequestDTO attendanceRequest() { - return new AttendanceRequestDTO(0L, 0, SUB_LECTURE_CODE); + return new AttendanceRequestDTO(0L, 1, SUB_LECTURE_CODE); } public static LectureDetailResponseDTO lectureDetail() { @@ -131,4 +132,8 @@ public static List lectureList() { return Stream.iterate(1, i -> i + 1).limit(LIST_SIZE) .map(i -> lectureRequest().toEntity()).toList(); } + + public static SubLecture subLecture(Lecture lecture) { + return new SubLecture(lecture, 1); + } } diff --git a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java index ef093a9d..5db70016 100644 --- a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java +++ b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java @@ -11,6 +11,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.sopt.makers.operation.config.ValueConfig; +import org.sopt.makers.operation.dto.lecture.AttendanceRequestDTO; import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; import org.sopt.makers.operation.entity.lecture.Lecture; @@ -71,4 +72,21 @@ void getLecture() { // verify verify(lectureRepository, times(1)).findById(anyLong()); } + + @DisplayName("출석 시작") + @Test + void startAttendance() { + // given + Lecture lecture = lectureRequest().toEntity(); + subLecture(lecture); + AttendanceRequestDTO request = attendanceRequest(); + + doReturn(Optional.of(lecture)).when(lectureRepository).findById(anyLong()); + + // when + lectureService.startAttendance(request); + + // verify + verify(lectureRepository, times(1)).findById(anyLong()); + } } \ No newline at end of file From 7bca58ba5c7ca564e85736b6845c5809cd8d48bc Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 13:27:30 +0900 Subject: [PATCH 15/19] =?UTF-8?q?[REFACTOR]=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=A2=85=EB=A3=8C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ScheduleController.java | 2 +- .../controller/web/LectureController.java | 4 +- .../operation/entity/lecture/Lecture.java | 2 +- .../operation/service/LectureService.java | 11 +++- .../operation/service/LectureServiceImpl.java | 65 ++++++++++--------- 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/controller/ScheduleController.java b/src/main/java/org/sopt/makers/operation/controller/ScheduleController.java index 8ede0853..5b7a673e 100644 --- a/src/main/java/org/sopt/makers/operation/controller/ScheduleController.java +++ b/src/main/java/org/sopt/makers/operation/controller/ScheduleController.java @@ -16,7 +16,7 @@ public class ScheduleController { @Scheduled(cron = "0 0 0 ? * SUN") public void endLecture() { - lectureService.finishLecture(); + lectureService.endLectures(); } } diff --git a/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java b/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java index 9cc4e264..156cc045 100644 --- a/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java +++ b/src/main/java/org/sopt/makers/operation/controller/web/LectureController.java @@ -76,8 +76,8 @@ private URI getURI(Long lectureId) { @ApiOperation(value = "세션 종료 후 출석 점수 갱신") @PatchMapping("/{lectureId}") - public ResponseEntity finishLecture(@PathVariable Long lectureId) { - lectureService.finishLecture(lectureId); + public ResponseEntity endLecture(@PathVariable Long lectureId) { + lectureService.endLecture(lectureId); return ResponseEntity.ok(success(SUCCESS_UPDATE_MEMBER_SCORE.getMessage())); } diff --git a/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java b/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java index 5027ce8f..0125fbe3 100644 --- a/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java +++ b/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java @@ -74,7 +74,7 @@ public void updateStatus(LectureStatus status) { this.lectureStatus = status; } - public void finish() { + public void updateToEnd() { this.lectureStatus = LectureStatus.END; attendances.forEach(Attendance::updateMemberScore); } diff --git a/src/main/java/org/sopt/makers/operation/service/LectureService.java b/src/main/java/org/sopt/makers/operation/service/LectureService.java index 6a16ee0c..e739b0ff 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureService.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureService.java @@ -11,13 +11,18 @@ public interface LectureService { + /** WEB **/ long createLecture(LectureRequestDTO requestDTO); LecturesResponseDTO getLectures(int generation, Part part); + AttendanceResponseDTO startAttendance(AttendanceRequestDTO requestDTO); + void endLecture(Long lectureId); + + /** SCHEDULER **/ + void endLectures(); + + /** APP **/ LectureGetResponseDTO getCurrentLecture(Long playGroundId); LectureResponseDTO getLecture(Long lectureId); - AttendanceResponseDTO startAttendance(AttendanceRequestDTO requestDTO); - void finishLecture(Long lectureId); - void finishLecture(); LectureCurrentRoundResponseDTO getCurrentLectureRound(Long lectureId); void deleteLecture(Long lectureId); LectureDetailResponseDTO getLectureDetail(Long lectureId); diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 2571d36f..56fe9f76 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -113,13 +113,13 @@ public LectureResponseDTO getLecture(Long lectureId) { @Transactional public AttendanceResponseDTO startAttendance(AttendanceRequestDTO requestDTO) { val lecture = findLecture(requestDTO.lectureId()); - checkValidAttendance(lecture, requestDTO.round()); + checkStartAttendanceValidity(lecture, requestDTO.round()); val subLecture = getSubLecture(lecture, requestDTO.round()); subLecture.startAttendance(requestDTO.code()); return AttendanceResponseDTO.of(lecture, subLecture); } - private void checkValidAttendance(Lecture lecture, int round) { + private void checkStartAttendanceValidity(Lecture lecture, int round) { if (lecture.isEnd()) { throw new LectureException(END_LECTURE.getName()); } else if (round == 2 && lecture.isBefore()) { @@ -136,46 +136,49 @@ private SubLecture getSubLecture(Lecture lecture, int round) { @Override @Transactional - public void finishLecture(Long lectureId) { + public void endLecture(Long lectureId) { val lecture = findLecture(lectureId); - val now = LocalDateTime.now(); - if (now.isBefore(lecture.getEndDate())) { - throw new IllegalStateException(NOT_END_TIME_YET.getName()); - } - lecture.finish(); - - List memberPgIds = lecture.getAttendances().stream() - .map(attendance -> String.valueOf(attendance.getMember().getPlaygroundId())) - .filter(id -> !id.equals("null")) - .toList(); - - val alarmTitle = lecture.getName() + " " + valueConfig.getALARM_MESSAGE_TITLE(); - alarmSender.send(new AlarmSenderDTO(alarmTitle, valueConfig.getALARM_MESSAGE_CONTENT(), memberPgIds, NEWS, null)); + checkEndLectureValidity(lecture); + lecture.updateToEnd(); + sendAlarm(lecture); } - /** APP **/ + /** SCHEDULER **/ @Override @Transactional - public void finishLecture() { + public void endLectures() { val lectures = lectureRepository.findLecturesToBeEnd(); - lectures.forEach(Lecture::finish); - - List memberPgIds; - for (val lecture : lectures) { - memberPgIds = new ArrayList<>(); - for (val attendance : lecture.getAttendances()) { - val playgroundId = attendance.getMember().getPlaygroundId(); - if (Objects.nonNull(playgroundId)) { - memberPgIds.add(String.valueOf(attendance.getMember().getPlaygroundId())); - } - } + lectures.forEach(lecture -> endLecture(lecture.getId())); + } - val alarmTitle = lecture.getName() + " " + valueConfig.getALARM_MESSAGE_TITLE(); - alarmSender.send(new AlarmSenderDTO(alarmTitle, valueConfig.getALARM_MESSAGE_CONTENT(), memberPgIds, NEWS, null)); + private void checkEndLectureValidity(Lecture lecture) { + val now = LocalDateTime.now(); + if (now.isBefore(lecture.getEndDate())) { + throw new LectureException(NOT_END_TIME_YET.getName()); } } + private void sendAlarm(Lecture lecture) { + val alarmTitle = getAlarmTitle(lecture); + val alarmContent = valueConfig.getALARM_MESSAGE_CONTENT(); + val memberPlaygroundIds = getMemberPlaygroundIds(lecture); + alarmSender.send(new AlarmSenderDTO(alarmTitle, alarmContent, memberPlaygroundIds, NEWS, null)); + } + + private List getMemberPlaygroundIds(Lecture lecture) { + return lecture.getAttendances().stream() + .map(attendance -> String.valueOf(attendance.getMember().getPlaygroundId())) + .filter(id -> !id.equals("null")) + .toList(); + } + + private String getAlarmTitle(Lecture lecture) { + return lecture.getName() + " " + valueConfig.getALARM_MESSAGE_TITLE(); + } + + /** APP **/ + @Override public LectureGetResponseDTO getCurrentLecture(Long playGroundId) { val now = LocalDateTime.now(); From 39e5a52895232369b10374113f4afba8f5e21e65 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 13:32:18 +0900 Subject: [PATCH 16/19] =?UTF-8?q?[TEST]=20=EC=84=B8=EC=85=98=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../operation/service/LectureServiceImpl.java | 3 +-- .../operation/fixture/LectureFixture.java | 6 ++++++ .../service/LectureServiceImplTest.java | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 56fe9f76..08d85ad7 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -153,8 +153,7 @@ public void endLectures() { } private void checkEndLectureValidity(Lecture lecture) { - val now = LocalDateTime.now(); - if (now.isBefore(lecture.getEndDate())) { + if (!lecture.isEnd()) { throw new LectureException(NOT_END_TIME_YET.getName()); } } diff --git a/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java index 898bf7d1..cad87a67 100644 --- a/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java +++ b/src/test/java/org/sopt/makers/operation/fixture/LectureFixture.java @@ -43,6 +43,12 @@ public static LectureRequestDTO lectureRequest() { .build(); } + public static Lecture lectureEnd() { + Lecture lecture = lectureRequest().toEntity(); + lecture.updateToEnd(); + return lecture; + } + public static long lectureId() { return 0L; } diff --git a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java index 5db70016..e37a615f 100644 --- a/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java +++ b/src/test/java/org/sopt/makers/operation/service/LectureServiceImplTest.java @@ -15,6 +15,7 @@ import org.sopt.makers.operation.dto.lecture.LectureResponseDTO; import org.sopt.makers.operation.dto.lecture.LecturesResponseDTO; import org.sopt.makers.operation.entity.lecture.Lecture; +import org.sopt.makers.operation.external.api.AlarmSender; import org.sopt.makers.operation.repository.lecture.LectureRepository; import org.sopt.makers.operation.repository.member.MemberRepository; @@ -33,6 +34,8 @@ class LectureServiceImplTest { @Mock private MemberRepository memberRepository; @Mock + private AlarmSender alarmSender; + @Mock ValueConfig valueConfig; @DisplayName("세션 목록 조회") @@ -89,4 +92,20 @@ void startAttendance() { // verify verify(lectureRepository, times(1)).findById(anyLong()); } + + @DisplayName("세션 종료") + @Test + void endLecture() { + // given + long lectureId = lectureId(); + Lecture lecture = lectureEnd(); + + doReturn(Optional.of(lecture)).when(lectureRepository).findById(anyLong()); + + // when + lectureService.endLecture(lectureId); + + // verify + verify(lectureRepository, times(1)).findById(anyLong()); + } } \ No newline at end of file From 4a99d3f3138f80dd52897a3bdf0cb056261d4e88 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 14:48:58 +0900 Subject: [PATCH 17/19] =?UTF-8?q?[REFACTOR]=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../makers/operation/config/ValueConfig.java | 3 + .../controller/app/AppLectureController.java | 13 +- ...eDTO.java => TodayLectureResponseDTO.java} | 38 ++-- .../operation/entity/lecture/Lecture.java | 13 +- .../AttendanceCustomRepository.java | 3 +- .../attendance/AttendanceRepositoryImpl.java | 33 +--- .../operation/service/LectureService.java | 11 +- .../operation/service/LectureServiceImpl.java | 173 +++++++++--------- 8 files changed, 138 insertions(+), 149 deletions(-) rename src/main/java/org/sopt/makers/operation/dto/lecture/{LectureGetResponseDTO.java => TodayLectureResponseDTO.java} (63%) diff --git a/src/main/java/org/sopt/makers/operation/config/ValueConfig.java b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java index 9c36a59e..e979ce11 100644 --- a/src/main/java/org/sopt/makers/operation/config/ValueConfig.java +++ b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java @@ -15,4 +15,7 @@ public class ValueConfig { private String ALARM_MESSAGE_CONTENT; private final int SUB_LECTURE_MAX_ROUND = 2; + private final String ETC_MESSAGE = "출석 점수가 반영되지 않아요."; + private final String SEMINAR_MESSAGE = ""; + private final String EVENT_MESSAGE = "행사도 참여하고, 출석점수도 받고, 일석이조!"; } diff --git a/src/main/java/org/sopt/makers/operation/controller/app/AppLectureController.java b/src/main/java/org/sopt/makers/operation/controller/app/AppLectureController.java index 663aa109..309af9e0 100644 --- a/src/main/java/org/sopt/makers/operation/controller/app/AppLectureController.java +++ b/src/main/java/org/sopt/makers/operation/controller/app/AppLectureController.java @@ -1,7 +1,5 @@ package org.sopt.makers.operation.controller.app; - -import static java.util.Objects.*; import static org.sopt.makers.operation.common.ResponseMessage.*; import io.swagger.annotations.ApiOperation; @@ -19,11 +17,14 @@ @RequiredArgsConstructor @RequestMapping("/api/v1/app/lectures") public class AppLectureController { + private final LectureService lectureService; - @ApiOperation(value = "단일 세미나 상태 조회") + + @ApiOperation(value = "진행 중인 세미나 상태 조회") @GetMapping public ResponseEntity getLecture(@ApiIgnore Principal principal) { - val response = lectureService.getCurrentLecture(getMemberId(principal)); + val memberPlaygroundId = Long.parseLong(principal.getName()); + val response = lectureService.getTodayLecture(memberPlaygroundId); return ResponseEntity.ok(ApiResponse.success(SUCCESS_SINGLE_GET_LECTURE.getMessage(), response)); } @@ -33,8 +34,4 @@ public ResponseEntity getRound(@PathVariable("lectureId") Long lect val response = lectureService.getCurrentLectureRound(lectureId); return ResponseEntity.ok(ApiResponse.success(SUCCESS_GET_LECTURE_ROUND.getMessage(), response)); } - - private Long getMemberId(Principal principal) { - return nonNull(principal) ? Long.valueOf(principal.getName()) : null; - } } diff --git a/src/main/java/org/sopt/makers/operation/dto/lecture/LectureGetResponseDTO.java b/src/main/java/org/sopt/makers/operation/dto/lecture/TodayLectureResponseDTO.java similarity index 63% rename from src/main/java/org/sopt/makers/operation/dto/lecture/LectureGetResponseDTO.java rename to src/main/java/org/sopt/makers/operation/dto/lecture/TodayLectureResponseDTO.java index 7b1f9696..40685563 100644 --- a/src/main/java/org/sopt/makers/operation/dto/lecture/LectureGetResponseDTO.java +++ b/src/main/java/org/sopt/makers/operation/dto/lecture/TodayLectureResponseDTO.java @@ -11,7 +11,7 @@ import java.util.stream.Collectors; @Builder -public record LectureGetResponseDTO( +public record TodayLectureResponseDTO( LectureResponseType type, Long id, String location, @@ -21,9 +21,9 @@ public record LectureGetResponseDTO( String message, List attendances ) { - public static LectureGetResponseDTO of(LectureResponseType type, Lecture lecture, String message, List attendances) { + public static TodayLectureResponseDTO of(LectureResponseType type, Lecture lecture, String message, List attendances) { - return LectureGetResponseDTO.builder() + return TodayLectureResponseDTO.builder() .type(type) .id(lecture.getId()) .location(lecture.getPlace()) @@ -40,22 +40,22 @@ public static LectureGetResponseDTO of(LectureResponseType type, Lecture lecture private static DateTimeFormatter convertFormat() { return DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); } -} - -@Builder -record LectureGetResponseVO( - AttendanceStatus status, - String attendedAt -) { - public static LectureGetResponseVO of(AttendanceStatus status, LocalDateTime attendedAt) { - return LectureGetResponseVO.builder() - .status(status) - .attendedAt(attendedAt.format((convertFormat()))) - .build(); - } - - private static DateTimeFormatter convertFormat() { - return DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + @Builder + record LectureGetResponseVO( + AttendanceStatus status, + String attendedAt + + ) { + public static LectureGetResponseVO of(AttendanceStatus status, LocalDateTime attendedAt) { + return LectureGetResponseVO.builder() + .status(status) + .attendedAt(attendedAt.format((convertFormat()))) + .build(); + } + + private static DateTimeFormatter convertFormat() { + return DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + } } } diff --git a/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java b/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java index 0125fbe3..8fd2b9af 100644 --- a/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java +++ b/src/main/java/org/sopt/makers/operation/entity/lecture/Lecture.java @@ -1,6 +1,7 @@ package org.sopt.makers.operation.entity.lecture; import static javax.persistence.GenerationType.*; +import static org.sopt.makers.operation.entity.lecture.LectureStatus.*; import java.time.LocalDateTime; import java.util.ArrayList; @@ -67,7 +68,7 @@ public Lecture(String name, Part part, int generation, String place, LocalDateTi this.startDate = startDate; this.endDate = endDate; this.attribute = attribute; - this.lectureStatus = LectureStatus.BEFORE; + this.lectureStatus = BEFORE; } public void updateStatus(LectureStatus status) { @@ -75,15 +76,19 @@ public void updateStatus(LectureStatus status) { } public void updateToEnd() { - this.lectureStatus = LectureStatus.END; + this.lectureStatus = END; attendances.forEach(Attendance::updateMemberScore); } public boolean isEnd() { - return this.lectureStatus.equals(LectureStatus.END); + return this.lectureStatus.equals(END); } public boolean isBefore() { - return this.lectureStatus.equals(LectureStatus.BEFORE); + return this.lectureStatus.equals(BEFORE); + } + + public boolean isFirst() { + return this.lectureStatus.equals(FIRST); } } diff --git a/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceCustomRepository.java b/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceCustomRepository.java index dcbd655e..40e8f7cf 100644 --- a/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceCustomRepository.java +++ b/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceCustomRepository.java @@ -13,7 +13,6 @@ public interface AttendanceCustomRepository { List findAttendanceByMemberId(Long memberId); List findByLecture(Long lectureId, Part part, Pageable pageable); List findByMember(Member member); - List findCurrentAttendanceByMember(Long playGroundId); - List findSubAttendanceByAttendanceId(Long attendanceId); + List findToday(long memberPlaygroundId); int countByLectureIdAndPart(long lectureId, Part part); } diff --git a/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java b/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java index 497ae2f9..b84101a9 100644 --- a/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java +++ b/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java @@ -8,6 +8,7 @@ import static org.sopt.makers.operation.entity.QSubLecture.*; import static org.sopt.makers.operation.entity.lecture.QLecture.*; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; @@ -18,6 +19,7 @@ import org.sopt.makers.operation.entity.Attendance; import org.sopt.makers.operation.entity.Member; import org.sopt.makers.operation.entity.Part; +import org.sopt.makers.operation.entity.QMember; import org.sopt.makers.operation.entity.SubAttendance; import org.sopt.makers.operation.entity.lecture.LectureStatus; import org.springframework.data.domain.Pageable; @@ -81,40 +83,25 @@ public List findByMember(Member member) { } @Override - public List findCurrentAttendanceByMember(Long playGroundId) { - val now = LocalDateTime.now(); - val today = now.toLocalDate(); + public List findToday(long memberPlaygroundId) { + val today = LocalDate.now(); val startOfDay = today.atStartOfDay(); val endOfDay = LocalDateTime.of(today, LocalTime.MAX); - return queryFactory - .select(attendance) - .from(attendance) + .selectFrom(attendance) .leftJoin(attendance.lecture, lecture).fetchJoin() .leftJoin(attendance.member, member).fetchJoin() + .leftJoin(attendance.subAttendances, subAttendance).fetchJoin().distinct() + .leftJoin(subAttendance.subLecture, subLecture).fetchJoin() .where( + member.playgroundId.eq(memberPlaygroundId), + member.generation.eq(generationConfig.getCurrentGeneration()), lecture.part.eq(member.part).or(lecture.part.eq(Part.ALL)), - lecture.startDate.between(startOfDay, endOfDay), - member.playgroundId.eq(playGroundId), - member.generation.eq(generationConfig.getCurrentGeneration()) - ) + lecture.startDate.between(startOfDay, endOfDay)) .orderBy(lecture.startDate.asc()) .fetch(); } - @Override - public List findSubAttendanceByAttendanceId(Long attendanceId) { - return queryFactory - .select(subAttendance) - .from(subAttendance) - .leftJoin(subAttendance.subLecture, subLecture).fetchJoin() - .where( - subAttendance.attendance.id.eq(attendanceId) - ) - .orderBy(subAttendance.createdDate.asc()) - .fetch(); - } - @Override public int countByLectureIdAndPart(long lectureId, Part part) { return Math.toIntExact(queryFactory diff --git a/src/main/java/org/sopt/makers/operation/service/LectureService.java b/src/main/java/org/sopt/makers/operation/service/LectureService.java index e739b0ff..8659e21e 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureService.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureService.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.service; -import org.sopt.makers.operation.dto.lecture.LectureGetResponseDTO; +import org.sopt.makers.operation.dto.lecture.TodayLectureResponseDTO; import org.sopt.makers.operation.dto.lecture.AttendanceRequestDTO; import org.sopt.makers.operation.dto.lecture.AttendanceResponseDTO; import org.sopt.makers.operation.dto.lecture.LectureRequestDTO; @@ -14,17 +14,16 @@ public interface LectureService { /** WEB **/ long createLecture(LectureRequestDTO requestDTO); LecturesResponseDTO getLectures(int generation, Part part); + LectureResponseDTO getLecture(Long lectureId); AttendanceResponseDTO startAttendance(AttendanceRequestDTO requestDTO); void endLecture(Long lectureId); + void deleteLecture(Long lectureId); + LectureDetailResponseDTO getLectureDetail(Long lectureId); /** SCHEDULER **/ void endLectures(); /** APP **/ - LectureGetResponseDTO getCurrentLecture(Long playGroundId); - LectureResponseDTO getLecture(Long lectureId); + TodayLectureResponseDTO getTodayLecture(long memberPlaygroundId); LectureCurrentRoundResponseDTO getCurrentLectureRound(Long lectureId); - void deleteLecture(Long lectureId); - LectureDetailResponseDTO getLectureDetail(Long lectureId); - } diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index 08d85ad7..b445ba95 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -1,7 +1,8 @@ package org.sopt.makers.operation.service; -import static java.util.Objects.nonNull; import static org.sopt.makers.operation.common.ExceptionMessage.*; +import static org.sopt.makers.operation.common.ExceptionMessage.NO_SESSION; +import static org.sopt.makers.operation.dto.lecture.LectureResponseType.*; import static org.sopt.makers.operation.entity.AttendanceStatus.*; import static org.sopt.makers.operation.entity.alarm.Attribute.*; import static org.sopt.makers.operation.entity.lecture.LectureStatus.*; @@ -143,6 +144,34 @@ public void endLecture(Long lectureId) { sendAlarm(lecture); } + @Override + @Transactional + public void deleteLecture(Long lectureId) { + val lecture = findLecture(lectureId); + if (lecture.isEnd()) { + restoreAttendances(lecture.getAttendances()); + } + subAttendanceRepository.deleteAllBySubLectureIn(lecture.getSubLectures()); + subLectureRepository.deleteAllByLecture(lecture); + attendanceRepository.deleteAllByLecture(lecture); + lectureRepository.deleteById(lectureId); + } + + private void restoreAttendances(List attendances) { + attendances.forEach(Attendance::revertMemberScore); + } + + @Override + public LectureDetailResponseDTO getLectureDetail(Long lectureId) { + val lecture = findLecture(lectureId); + return LectureDetailResponseDTO.of(lecture); + } + + private Lecture findLecture(Long id) { + return lectureRepository.findById(id) + .orElseThrow(() -> new LectureException(INVALID_LECTURE.getName())); + } + /** SCHEDULER **/ @Override @@ -179,65 +208,77 @@ private String getAlarmTitle(Lecture lecture) { /** APP **/ @Override - public LectureGetResponseDTO getCurrentLecture(Long playGroundId) { - val now = LocalDateTime.now(); - - val attendances = attendanceRepository.findCurrentAttendanceByMember(playGroundId); + public TodayLectureResponseDTO getTodayLecture(long memberPlaygroundId) { + val attendances = attendanceRepository.findToday(memberPlaygroundId); + checkAttendancesSize(attendances); if (attendances.isEmpty()) { - return new LectureGetResponseDTO(LectureResponseType.NO_SESSION, 0L, "", "", "", "", "", Collections.emptyList()); + return getEmptyResponse(); } - if (attendances.size() > 2) { - throw new LectureException(INVALID_COUNT_SESSION.getName()); - } - - // 현재 출석과 Lecture 가져오기 - val currentAttendance = getCurrentAttendance(attendances, now); - val currentLecture = currentAttendance.getLecture(); - val lectureType = getLectureResponseType(currentLecture); + val attendance = getNowAttendance(attendances); + val lecture = attendance.getLecture(); + val responseType = getResponseType(lecture); + val message = getMessage(lecture.getAttribute()); - if (lectureType.equals(LectureResponseType.NO_ATTENDANCE)) { - val message = "출석 점수가 반영되지 않아요."; - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); + if (responseType.equals(NO_ATTENDANCE) || lecture.isBefore()) { + return TodayLectureResponseDTO.of(responseType, lecture, message, Collections.emptyList()); } - val subAttendances = attendanceRepository.findSubAttendanceByAttendanceId(currentAttendance.getId()); - - val firstSubLectureAttendance = subAttendances.get(0); - val secondSubLectureAttendance = subAttendances.get(1); + val subAttendances = attendance.getSubAttendances(); + val subAttendance = lecture.isFirst() ? subAttendances.get(0) : subAttendances.get(1); + return getTodayLectureResponse(subAttendance, responseType, lecture); + } - val firstSubLectureAttendanceStatus = firstSubLectureAttendance.getStatus(); - val secondSubLectureAttendanceStatus = secondSubLectureAttendance.getStatus(); + private TodayLectureResponseDTO getEmptyResponse() { + return TodayLectureResponseDTO.builder() + .type(LectureResponseType.NO_SESSION) + .id(0L) + .location("") + .name("") + .startDate("") + .endDate("") + .message("") + .attendances(Collections.emptyList()) + .build(); + } - val firstSessionStart = firstSubLectureAttendance.getSubLecture().getStartAt(); - val secondSessionStart = secondSubLectureAttendance.getSubLecture().getStartAt(); + private void checkAttendancesSize(List attendances) { + if (attendances.size() > valueConfig.getSUB_LECTURE_MAX_ROUND()) { + throw new LectureException(INVALID_COUNT_SESSION.getName()); + } + } - val message = (currentLecture.getAttribute() == Attribute.SEMINAR) ? "" : "행사도 참여하고, 출석점수도 받고, 일석이조!"; + private Attendance getNowAttendance(List attendances) { + val index = getAttendanceIndex(); + return attendances.get(index); + } - // Lecture 시작 전 혹은 1차 출석 시작 전 - if (now.isBefore(currentLecture.getStartDate()) || !nonNull(firstSessionStart)) { - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); - } + private int getAttendanceIndex() { + return (LocalDateTime.now().getHour() >= 16) ? 1 : 0; + } - // 1차 출석 시작, 2차 출석 시작 전 - if (now.isAfter(firstSessionStart) && !nonNull(secondSessionStart)) { - // 1차 출석 중 결석인 상태 - if (now.isBefore(firstSessionStart.plusMinutes(10)) && firstSubLectureAttendanceStatus.equals(ABSENT)) { - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.emptyList()); - } + private LectureResponseType getResponseType(Lecture lecture) { + val attribute = lecture.getAttribute(); + return attribute.equals(Attribute.ETC) ? NO_ATTENDANCE : HAS_ATTENDANCE; + } - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.singletonList(firstSubLectureAttendance)); - } + private String getMessage(Attribute attribute) { + return switch (attribute) { + case SEMINAR -> valueConfig.getSEMINAR_MESSAGE(); + case EVENT -> valueConfig.getEVENT_MESSAGE(); + case ETC -> valueConfig.getETC_MESSAGE(); + }; + } - // 2차 출석 시작 이후 - if (now.isAfter(secondSessionStart)) { - // 2차 출석 중 결석인 상태 - if (now.isBefore(secondSessionStart.plusMinutes(10)) && secondSubLectureAttendanceStatus.equals(ABSENT)) { - return LectureGetResponseDTO.of(lectureType, currentLecture, message, Collections.singletonList(firstSubLectureAttendance)); - } + private TodayLectureResponseDTO getTodayLectureResponse(SubAttendance subAttendance, LectureResponseType responseType, Lecture lecture) { + val subLecture = subAttendance.getSubLecture(); + val isOnAttendanceCheck = LocalDateTime.now().isBefore(subLecture.getStartAt().plusMinutes(10)); + val message = getMessage(lecture.getAttribute()); + if (isOnAttendanceCheck && subAttendance.getStatus().equals(ABSENT)) { + return TodayLectureResponseDTO.of(responseType, lecture, message, Collections.emptyList()); } - return LectureGetResponseDTO.of(lectureType, currentLecture, message, subAttendances); + return TodayLectureResponseDTO.of(responseType, lecture, message, Collections.singletonList(subAttendance)); } @Override @@ -287,46 +328,4 @@ public LectureCurrentRoundResponseDTO getCurrentLectureRound(Long lectureId) { return LectureCurrentRoundResponseDTO.of(subLecture); } - - @Override - @Transactional - public void deleteLecture(Long lectureId) { - val lecture = lectureRepository.find(lectureId) - .orElseThrow(() -> new LectureException(INVALID_LECTURE.getName())); - - // 출석 종료된 세션: 출석 점수 갱신 전으로 복구 - if (lecture.getLectureStatus().equals(END)) { - lecture.getAttendances().forEach(Attendance::revertMemberScore); - } - - // 연관 관계의 객체 삭제 후 세션 삭제 - subAttendanceRepository.deleteAllBySubLectureIn(lecture.getSubLectures()); - subLectureRepository.deleteAllByLecture(lecture); - attendanceRepository.deleteAllByLecture(lecture); - lectureRepository.deleteById(lectureId); - // lectureRepository.delete(lecture); //TODO: 에러 원인 파악 필요 - } - - @Override - public LectureDetailResponseDTO getLectureDetail(Long lectureId) { - val lecture = findLecture(lectureId); - return LectureDetailResponseDTO.of(lecture); - } - - private Lecture findLecture(Long id) { - return lectureRepository.findById(id) - .orElseThrow(() -> new LectureException(INVALID_LECTURE.getName())); - } - - private Attendance getCurrentAttendance(List attendances, LocalDateTime now) { - val lectureSize = attendances.size(); - val currentHour = now.getHour(); - - val attendanceIndex = (lectureSize == 2 && currentHour >= 16) ? 1 : 0; - return attendances.get(attendanceIndex); - } - - private LectureResponseType getLectureResponseType(Lecture currentLecture) { - return (currentLecture.getAttribute() != Attribute.ETC) ? LectureResponseType.HAS_ATTENDANCE : LectureResponseType.NO_ATTENDANCE; - } } From 52013cea0323e0d5eccadee4fe517f64811c77d1 Mon Sep 17 00:00:00 2001 From: thguss Date: Fri, 19 Jan 2024 15:12:37 +0900 Subject: [PATCH 18/19] =?UTF-8?q?[REFACTOR]=20=EC=B6=9C=EC=84=9D=20?= =?UTF-8?q?=EC=B0=A8=EC=88=98=20=EC=A1=B0=ED=9A=8C=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../operation/service/LectureService.java | 6 +- .../operation/service/LectureServiceImpl.java | 84 ++++++++++--------- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/sopt/makers/operation/service/LectureService.java b/src/main/java/org/sopt/makers/operation/service/LectureService.java index 8659e21e..b133cc73 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureService.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureService.java @@ -14,16 +14,16 @@ public interface LectureService { /** WEB **/ long createLecture(LectureRequestDTO requestDTO); LecturesResponseDTO getLectures(int generation, Part part); - LectureResponseDTO getLecture(Long lectureId); + LectureResponseDTO getLecture(long lectureId); AttendanceResponseDTO startAttendance(AttendanceRequestDTO requestDTO); void endLecture(Long lectureId); void deleteLecture(Long lectureId); - LectureDetailResponseDTO getLectureDetail(Long lectureId); + LectureDetailResponseDTO getLectureDetail(long lectureId); /** SCHEDULER **/ void endLectures(); /** APP **/ TodayLectureResponseDTO getTodayLecture(long memberPlaygroundId); - LectureCurrentRoundResponseDTO getCurrentLectureRound(Long lectureId); + LectureCurrentRoundResponseDTO getCurrentLectureRound(long lectureId); } diff --git a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java index b445ba95..dc4c6fcd 100644 --- a/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/LectureServiceImpl.java @@ -7,6 +7,7 @@ import static org.sopt.makers.operation.entity.alarm.Attribute.*; import static org.sopt.makers.operation.entity.lecture.LectureStatus.*; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; @@ -105,7 +106,7 @@ public LecturesResponseDTO getLectures(int generation, Part part) { } @Override - public LectureResponseDTO getLecture(Long lectureId) { + public LectureResponseDTO getLecture(long lectureId) { Lecture lecture = findLecture(lectureId); return LectureResponseDTO.of(lecture); } @@ -128,13 +129,6 @@ private void checkStartAttendanceValidity(Lecture lecture, int round) { } } - private SubLecture getSubLecture(Lecture lecture, int round) { - return lecture.getSubLectures().stream() - .filter(l -> l.getRound() == round) - .findFirst() - .orElseThrow(() -> new SubLectureException(NO_SUB_LECTURE_EQUAL_ROUND.getName())); - } - @Override @Transactional public void endLecture(Long lectureId) { @@ -162,7 +156,7 @@ private void restoreAttendances(List attendances) { } @Override - public LectureDetailResponseDTO getLectureDetail(Long lectureId) { + public LectureDetailResponseDTO getLectureDetail(long lectureId) { val lecture = findLecture(lectureId); return LectureDetailResponseDTO.of(lecture); } @@ -282,50 +276,62 @@ private TodayLectureResponseDTO getTodayLectureResponse(SubAttendance subAttenda } @Override - public LectureCurrentRoundResponseDTO getCurrentLectureRound(Long lectureId) { - val now = LocalDateTime.now(); - val today = now.toLocalDate(); - val startOfDay = today.atStartOfDay(); - val endOfDay = LocalDateTime.of(today, LocalTime.MAX); - - val lecture = lectureRepository.findById(lectureId) - .orElseThrow(() -> new LectureException(INVALID_LECTURE.getName())); - - val lectureStartDate = lecture.getStartDate(); - val lectureStatus = lecture.getLectureStatus(); + public LectureCurrentRoundResponseDTO getCurrentLectureRound(long lectureId) { + val lecture = findLecture(lectureId); + val subLecture = getSubLecture(lecture); + checkLectureExist(lecture); + checkLectureBefore(lecture); + checkEndAttendance(subLecture); + checkLectureEnd(lecture); + return LectureCurrentRoundResponseDTO.of(subLecture); + } - val subLectures = lecture.getSubLectures(); - subLectures.sort(Comparator.comparing(SubLecture::getRound)); + private SubLecture getSubLecture(Lecture lecture) { + val status = lecture.getLectureStatus(); + val round = status.equals(FIRST) ? 1 : 2; + return getSubLecture(lecture, round); + } - val subLecture = lectureStatus.equals(FIRST) ? - subLectures.get(0) : subLectures.get(1); + private SubLecture getSubLecture(Lecture lecture, int round) { + return lecture.getSubLectures().stream() + .filter(l -> l.getRound() == round) + .findFirst() + .orElseThrow(() -> new SubLectureException(NO_SUB_LECTURE_EQUAL_ROUND.getName())); + } - if (lectureStartDate.isBefore(startOfDay) || lectureStartDate.isAfter(endOfDay)) { + private void checkLectureExist(Lecture lecture) { + val today = LocalDate.now(); + val startOfDay = today.atStartOfDay(); + val endOfDay = LocalDateTime.of(today, LocalTime.MAX); + val startAt = lecture.getStartDate(); + if (startAt.isBefore(startOfDay) || startAt.isAfter(endOfDay)) { throw new LectureException(NO_SESSION.getName()); } + } - if (lectureStatus.equals(BEFORE)) { + private void checkLectureBefore(Lecture lecture) { + if (lecture.isBefore()) { throw new LectureException(NOT_STARTED_ATTENDANCE.getName()); } + } - if (lectureStatus.equals(FIRST)) { - // 1차 출석이 마감되었을 때 - if (now.isAfter(subLecture.getStartAt().plusMinutes(10))) { - throw new LectureException(subLecture.getRound() + ENDED_ATTENDANCE.getName()); - } + private void checkEndAttendance(SubLecture subLecture) { + if (isEndAttendance(subLecture)) { + throw new LectureException(subLecture.getRound() + ENDED_ATTENDANCE.getName()); } + } - if (lectureStatus.equals(SECOND)) { - // 2차 출석이 마감되었을 때 - if (now.isAfter(subLecture.getStartAt().plusMinutes(10))) { - throw new LectureException(subLecture.getRound() + ENDED_ATTENDANCE.getName()); - } + private boolean isEndAttendance(SubLecture subLecture) { + val status = subLecture.getLecture().getLectureStatus(); + if (LocalDateTime.now().isAfter(subLecture.getStartAt().plusMinutes(10))) { + return status.equals(FIRST) || status.equals(SECOND); } + return false; + } - if (lectureStatus.equals(END)) { + private void checkLectureEnd(Lecture lecture) { + if (lecture.isEnd()) { throw new LectureException(END_LECTURE.getName()); } - - return LectureCurrentRoundResponseDTO.of(subLecture); } } From cb9f46536889f89b383f3c98f9d6131dcc6bbb95 Mon Sep 17 00:00:00 2001 From: thguss Date: Wed, 24 Jan 2024 00:58:44 +0900 Subject: [PATCH 19/19] =?UTF-8?q?[CHORE]=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../makers/operation/config/GenerationConfig.java | 13 ------------- .../sopt/makers/operation/config/ValueConfig.java | 2 ++ .../dto/lecture/AttendanceResponseDTO.java | 8 +++++++- .../attendance/AttendanceRepositoryImpl.java | 10 ++++------ .../makers/operation/service/AlarmServiceImpl.java | 9 ++++----- .../operation/service/AttendanceServiceImpl.java | 11 +++-------- .../makers/operation/service/MemberServiceImpl.java | 10 ++++------ 7 files changed, 24 insertions(+), 39 deletions(-) delete mode 100644 src/main/java/org/sopt/makers/operation/config/GenerationConfig.java diff --git a/src/main/java/org/sopt/makers/operation/config/GenerationConfig.java b/src/main/java/org/sopt/makers/operation/config/GenerationConfig.java deleted file mode 100644 index 890de985..00000000 --- a/src/main/java/org/sopt/makers/operation/config/GenerationConfig.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.sopt.makers.operation.config; - -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - - -@Getter -@Configuration -public class GenerationConfig { - @Value("${sopt.current.generation}") - private int currentGeneration; -} diff --git a/src/main/java/org/sopt/makers/operation/config/ValueConfig.java b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java index e979ce11..e38673ff 100644 --- a/src/main/java/org/sopt/makers/operation/config/ValueConfig.java +++ b/src/main/java/org/sopt/makers/operation/config/ValueConfig.java @@ -13,6 +13,8 @@ public class ValueConfig { private String ALARM_MESSAGE_TITLE; @Value("${sopt.alarm.message.content_end}") private String ALARM_MESSAGE_CONTENT; + @Value("${sopt.current.generation}") + private int GENERATION; private final int SUB_LECTURE_MAX_ROUND = 2; private final String ETC_MESSAGE = "출석 점수가 반영되지 않아요."; diff --git a/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java b/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java index ed025359..8e61faf9 100644 --- a/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java +++ b/src/main/java/org/sopt/makers/operation/dto/lecture/AttendanceResponseDTO.java @@ -3,12 +3,18 @@ import org.sopt.makers.operation.entity.SubLecture; import org.sopt.makers.operation.entity.lecture.Lecture; +import lombok.Builder; + +@Builder public record AttendanceResponseDTO( Long lectureId, Long subLectureId ) { public static AttendanceResponseDTO of(Lecture lecture, SubLecture subLecture) { - return new AttendanceResponseDTO(lecture.getId(), subLecture.getId()); + return AttendanceResponseDTO.builder() + .lectureId(lecture.getId()) + .subLectureId(subLecture.getId()) + .build(); } } diff --git a/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java b/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java index b84101a9..708592c1 100644 --- a/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java +++ b/src/main/java/org/sopt/makers/operation/repository/attendance/AttendanceRepositoryImpl.java @@ -15,12 +15,10 @@ import lombok.val; -import org.sopt.makers.operation.config.GenerationConfig; +import org.sopt.makers.operation.config.ValueConfig; import org.sopt.makers.operation.entity.Attendance; import org.sopt.makers.operation.entity.Member; import org.sopt.makers.operation.entity.Part; -import org.sopt.makers.operation.entity.QMember; -import org.sopt.makers.operation.entity.SubAttendance; import org.sopt.makers.operation.entity.lecture.LectureStatus; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @@ -35,7 +33,7 @@ public class AttendanceRepositoryImpl implements AttendanceCustomRepository { private final JPAQueryFactory queryFactory; - private final GenerationConfig generationConfig; + private final ValueConfig valueConfig; @Override public List findAttendanceByMemberId(Long memberId) { @@ -46,7 +44,7 @@ public List findAttendanceByMemberId(Long memberId) { .leftJoin(attendance.lecture, lecture) .where(attendance.member.id.eq(memberId), lecture.lectureStatus.eq(LectureStatus.END), - lecture.generation.eq(generationConfig.getCurrentGeneration()) + lecture.generation.eq(valueConfig.getGENERATION()) ) .orderBy(attendance.lecture.startDate.desc()) .fetch(); @@ -95,7 +93,7 @@ public List findToday(long memberPlaygroundId) { .leftJoin(subAttendance.subLecture, subLecture).fetchJoin() .where( member.playgroundId.eq(memberPlaygroundId), - member.generation.eq(generationConfig.getCurrentGeneration()), + member.generation.eq(valueConfig.getGENERATION()), lecture.part.eq(member.part).or(lecture.part.eq(Part.ALL)), lecture.startDate.between(startOfDay, endOfDay)) .orderBy(lecture.startDate.asc()) diff --git a/src/main/java/org/sopt/makers/operation/service/AlarmServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/AlarmServiceImpl.java index 08c79780..a08a42dc 100644 --- a/src/main/java/org/sopt/makers/operation/service/AlarmServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/AlarmServiceImpl.java @@ -5,6 +5,7 @@ import static org.sopt.makers.operation.entity.Part.*; import static org.sopt.makers.operation.entity.alarm.Status.*; +import org.sopt.makers.operation.config.ValueConfig; import org.sopt.makers.operation.dto.alarm.AlarmSendRequestDTO; import org.sopt.makers.operation.dto.alarm.AlarmSenderDTO; import org.sopt.makers.operation.dto.member.MemberSearchCondition; @@ -15,7 +16,6 @@ import org.sopt.makers.operation.external.api.PlayGroundServer; import org.sopt.makers.operation.repository.alarm.AlarmRepository; import org.sopt.makers.operation.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,13 +34,12 @@ @Service @RequiredArgsConstructor public class AlarmServiceImpl implements AlarmService { - @Value("${sopt.current.generation}") - private int currentGeneration; private final AlarmRepository alarmRepository; private final MemberRepository memberRepository; private final AlarmSender alarmSender; private final PlayGroundServer playGroundServer; + private final ValueConfig valueConfig; @Override @Transactional @@ -68,7 +67,7 @@ private List getTargetIdList(Alarm alarm) { return activeTargetList; } - val inactiveTargetList = getInactiveTargetList(currentGeneration, alarm.getPart()); + val inactiveTargetList = getInactiveTargetList(valueConfig.getGENERATION(), alarm.getPart()); return inactiveTargetList.stream() .filter(target -> !activeTargetList.contains(target)) .toList(); @@ -76,7 +75,7 @@ private List getTargetIdList(Alarm alarm) { private List getActiveTargetList(Part part) { part = part.equals(ALL) ? null : part; - val members = memberRepository.search(new MemberSearchCondition(part, currentGeneration)); + val members = memberRepository.search(new MemberSearchCondition(part, valueConfig.getGENERATION())); return members.stream() .filter(member -> nonNull(member.getPlaygroundId())) .map(member -> String.valueOf(member.getPlaygroundId())) diff --git a/src/main/java/org/sopt/makers/operation/service/AttendanceServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/AttendanceServiceImpl.java index 1d4e6645..7ac524b1 100644 --- a/src/main/java/org/sopt/makers/operation/service/AttendanceServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/AttendanceServiceImpl.java @@ -3,12 +3,10 @@ import static java.util.Objects.nonNull; import static org.sopt.makers.operation.common.ExceptionMessage.*; -import java.util.List; - +import org.sopt.makers.operation.config.ValueConfig; import org.sopt.makers.operation.dto.attendance.AttendanceMemberResponseDTO; import org.sopt.makers.operation.dto.attendance.SubAttendanceUpdateRequestDTO; import org.sopt.makers.operation.dto.attendance.SubAttendanceUpdateResponseDTO; -import org.sopt.makers.operation.dto.attendance.MemberResponseDTO; import lombok.val; import org.sopt.makers.operation.dto.attendance.*; import org.sopt.makers.operation.entity.AttendanceStatus; @@ -22,7 +20,6 @@ import org.sopt.makers.operation.exception.SubLectureException; import org.sopt.makers.operation.repository.lecture.SubLectureRepository; import org.sopt.makers.operation.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -42,9 +39,7 @@ public class AttendanceServiceImpl implements AttendanceService { private final MemberRepository memberRepository; private final SubLectureRepository subLectureRepository; private final AttendanceRepository attendanceRepository; - - @Value("${sopt.current.generation}") - private int currentGeneration; + private final ValueConfig valueConfig; @Override @Transactional @@ -81,7 +76,7 @@ public AttendancesResponseDTO findAttendancesByLecture(Long lectureId, Part part @Transactional public AttendResponseDTO attend(Long playGroundId, AttendRequestDTO requestDTO) { log.info("[Attendance: attend start] id: " + playGroundId); - val member = memberRepository.getMemberByPlaygroundIdAndGeneration(playGroundId, currentGeneration) + val member = memberRepository.getMemberByPlaygroundIdAndGeneration(playGroundId, valueConfig.getGENERATION()) .orElseThrow(() -> new MemberException(INVALID_MEMBER.getName())); val memberId = member.getId(); diff --git a/src/main/java/org/sopt/makers/operation/service/MemberServiceImpl.java b/src/main/java/org/sopt/makers/operation/service/MemberServiceImpl.java index d4885baf..e1f57251 100644 --- a/src/main/java/org/sopt/makers/operation/service/MemberServiceImpl.java +++ b/src/main/java/org/sopt/makers/operation/service/MemberServiceImpl.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import lombok.val; +import org.sopt.makers.operation.config.ValueConfig; import org.sopt.makers.operation.dto.attendance.AttendanceTotalCountVO; import org.sopt.makers.operation.dto.attendance.AttendanceTotalResponseDTO; import org.sopt.makers.operation.dto.attendance.AttendanceTotalVO; @@ -20,7 +21,6 @@ import org.sopt.makers.operation.exception.MemberException; import org.sopt.makers.operation.repository.attendance.AttendanceRepository; import org.sopt.makers.operation.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -34,9 +34,7 @@ public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; private final AttendanceRepository attendanceRepository; - - @Value("${sopt.current.generation}") - private int currentGeneration; + private final ValueConfig valueConfig; @Override public MembersResponseDTO getMemberList(Part part, int generation, Pageable pageable) { @@ -58,7 +56,7 @@ public MembersResponseDTO getMemberList(Part part, int generation, Pageable page @Override public AttendanceTotalResponseDTO getMemberTotalAttendance(Long playGroundId) { - val member = memberRepository.getMemberByPlaygroundIdAndGeneration(playGroundId, currentGeneration) + val member = memberRepository.getMemberByPlaygroundIdAndGeneration(playGroundId, valueConfig.getGENERATION()) .orElseThrow(() -> new MemberException(INVALID_MEMBER.getName())); val attendances = findAttendances(member); @@ -72,7 +70,7 @@ public AttendanceTotalResponseDTO getMemberTotalAttendance(Long playGroundId) { @Override public MemberScoreGetResponse getMemberScore(Long playGroundId) { - val member = memberRepository.getMemberByPlaygroundIdAndGeneration(playGroundId, currentGeneration) + val member = memberRepository.getMemberByPlaygroundIdAndGeneration(playGroundId, valueConfig.getGENERATION()) .orElseThrow(() -> new MemberException(INVALID_MEMBER.getName())); return MemberScoreGetResponse.of(member.getScore());