diff --git a/src/main/java/com/oronaminc/join/answer/dao/AnswerRepository.java b/src/main/java/com/oronaminc/join/answer/dao/AnswerRepository.java index d06e03a..dcaf09d 100644 --- a/src/main/java/com/oronaminc/join/answer/dao/AnswerRepository.java +++ b/src/main/java/com/oronaminc/join/answer/dao/AnswerRepository.java @@ -2,43 +2,44 @@ import com.oronaminc.join.answer.domain.Answer; import com.oronaminc.join.question.domain.Question; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + public interface AnswerRepository extends JpaRepository { Optional findByQuestionId(Long questionId); @Query(""" - SELECT a - FROM Answer a - JOIN FETCH a.member m - WHERE a.question.id = :questionId - ORDER BY a.createdAt DESC, a.id DESC - """) + SELECT a + FROM Answer a + JOIN FETCH a.member m + WHERE a.question.id = :questionId + ORDER BY a.createdAt ASC, a.id ASC + """) List findFirstPageByQuestionId( - @Param("questionId") Long questionId, - Pageable pageable + @Param("questionId") Long questionId, + Pageable pageable ); @Query(""" - SELECT a - FROM Answer a - JOIN FETCH a.member m - WHERE a.question.id = :questionId - AND (a.createdAt < :lastCreatedAt OR (a.createdAt = :lastCreatedAt AND a.id < :lastId)) - ORDER BY a.createdAt DESC, a.id DESC - """) + SELECT a + FROM Answer a + JOIN FETCH a.member m + WHERE a.question.id = :questionId + AND (a.createdAt > :lastCreatedAt OR (a.createdAt = :lastCreatedAt AND a.id > :lastId)) + ORDER BY a.createdAt ASC, a.id ASC + """) List findByQuestionIdWithCursor( - @Param("questionId") Long questionId, - @Param("lastCreatedAt") LocalDateTime lastCreatedAt, - @Param("lastId") Long lastId, - Pageable pageable + @Param("questionId") Long questionId, + @Param("lastCreatedAt") LocalDateTime lastCreatedAt, + @Param("lastId") Long lastId, + Pageable pageable ); void deleteByQuestionId(Long questionId); @@ -46,17 +47,17 @@ List findByQuestionIdWithCursor( void deleteByQuestionIn(List questions); @Query(""" - select count(distinct a.question.id) - from Answer a - where a.question.room.id = :roomId - """) + select count(distinct a.question.id) + from Answer a + where a.question.room.id = :roomId + """) Long countAnsweredQuestionsByRoomId(@Param("roomId") Long roomId); @Query(""" - select a - from Answer a - where a.question.id in :questionIds - """) + select a + from Answer a + where a.question.id in :questionIds + """) List findAllByQuestionIds(@Param("questionIds") List questionIds); } diff --git a/src/main/java/com/oronaminc/join/global/exception/ErrorCode.java b/src/main/java/com/oronaminc/join/global/exception/ErrorCode.java index 865658b..e710928 100644 --- a/src/main/java/com/oronaminc/join/global/exception/ErrorCode.java +++ b/src/main/java/com/oronaminc/join/global/exception/ErrorCode.java @@ -29,7 +29,7 @@ public enum ErrorCode { UNAUTHORIZED_UPDATE_AND_DELETE("PARTICIPANT-003", "발표방 수정 및 삭제 권한이 없습니다.", UNAUTHORIZED), UNAUTHORIZED_REPORT_READ("PARTICIPANT-004", "결과 리포트 조회 권한이 없습니다.", UNAUTHORIZED), UNAUTHORIZED_LIMIT_PARTICIPANT("PARTICIPANT-005", "인원이 가득 차 참가할 수 없습니다.", UNAUTHORIZED), - UNAUTHORIZED_NOT_JOIN_ROOM("PARTICIPANT-005", "발표방에 참여하지 않았습니다. 먼저 참여해주세요.", UNAUTHORIZED), + UNAUTHORIZED_NOT_JOIN_ROOM("PARTICIPANT-006", "발표방에 참여하지 않았습니다. 먼저 참여해주세요.", UNAUTHORIZED), FILE_UPLOAD_FAILED("FILE-001", "파일 업로드에 실패하였습니다.", INTERNAL_SERVER_ERROR), NOT_FOUND_FILE("FILE-002", "존재하지 않는 파일입니다.", NOT_FOUND), diff --git a/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java b/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java index 8332001..87f65f1 100644 --- a/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java +++ b/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java @@ -30,12 +30,12 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .csrf(csrf -> csrf.disable()) .cors(cors -> cors.configurationSource(corsConfigurationSource())) .authorizeHttpRequests(auth -> auth - .requestMatchers( - "/api/auth/guest", - "/api/auth/kakao", - "/login" - ) - .anonymous() + // .requestMatchers( + // "/api/auth/guest", + // "/api/auth/kakao", + // "/login" + // ) + // .anonymous() .requestMatchers( "/swagger-ui/**", "/swagger-resources/**", @@ -44,11 +44,14 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/login/oauth2/code/kakao", "/api/auth/logout", "/dev/**", - "/ws/**" + "/ws/**", + "/api/auth/guest", + "/api/auth/kakao", + "/login" ) .permitAll() - .requestMatchers("/ws/**").permitAll() - .anyRequest().authenticated() + .anyRequest() + .authenticated() ) .formLogin(AbstractHttpConfigurer::disable) .oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo @@ -62,7 +65,7 @@ public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowCredentials(true); configuration.setAllowedOriginPatterns(List.of("*")); - configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); + configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")); configuration.setAllowedHeaders(List.of("*")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); diff --git a/src/main/java/com/oronaminc/join/member/util/MyPageMapper.java b/src/main/java/com/oronaminc/join/member/util/MyPageMapper.java index ccdb1eb..bf1c3dd 100644 --- a/src/main/java/com/oronaminc/join/member/util/MyPageMapper.java +++ b/src/main/java/com/oronaminc/join/member/util/MyPageMapper.java @@ -4,35 +4,44 @@ import com.oronaminc.join.member.dto.MyRoomsGetResponse; import com.oronaminc.join.member.dto.ParticipationType; import com.oronaminc.join.participant.domain.Participant; +import com.oronaminc.join.participant.domain.ParticipantType; import com.oronaminc.join.room.domain.Room; -import java.util.Map; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.springframework.data.domain.Page; +import java.time.LocalDate; +import java.util.Map; + @NoArgsConstructor(access = AccessLevel.PRIVATE) public class MyPageMapper { public static MyRoomsGetResponse toMyRoomsGetResponse(Page response) { return MyRoomsGetResponse.builder() - .content(response.getContent()) - .currentPage(response.getNumber()) - .size(response.getSize()) - .totalElements(response.getTotalElements()) - .totalPages(response.getTotalPages()) - .build(); + .content(response.getContent()) + .currentPage(response.getNumber()) + .size(response.getSize()) + .totalElements(response.getTotalElements()) + .totalPages(response.getTotalPages()) + .build(); } public static MyRoomsDto toMyRoomsDto(Participant p, Map countMap) { Room room = p.getRoom(); + LocalDate date; + if (p.getParticipantType() == ParticipantType.PRESENTER) { + date = room.getCreatedAt().toLocalDate(); + } else { + date = p.getCreatedAt().toLocalDate(); + } return MyRoomsDto.builder() - .roomId(room.getId()) - .title(room.getTitle()) - .emojiCount(room.getEmojiCount()) - .status(room.getRoomStatus()) - .startedAt(room.getCreatedAt().toLocalDate()) - .participationType(ParticipationType.from(p.getParticipantType())) - .questions(countMap.getOrDefault(room.getId(), 0L)) - .build(); + .roomId(room.getId()) + .title(room.getTitle()) + .emojiCount(room.getEmojiCount()) + .status(room.getRoomStatus()) + .startedAt(date) + .participationType(ParticipationType.from(p.getParticipantType())) + .questions(countMap.getOrDefault(room.getId(), 0L)) + .build(); } } diff --git a/src/main/java/com/oronaminc/join/room/service/RoomService.java b/src/main/java/com/oronaminc/join/room/service/RoomService.java index 9f04704..cbf3cbe 100644 --- a/src/main/java/com/oronaminc/join/room/service/RoomService.java +++ b/src/main/java/com/oronaminc/join/room/service/RoomService.java @@ -1,16 +1,5 @@ package com.oronaminc.join.room.service; -import static com.oronaminc.join.global.exception.ErrorCode.*; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import com.oronaminc.join.answer.domain.Answer; import com.oronaminc.join.answer.service.AnswerReader; import com.oronaminc.join.document.domain.Document; @@ -27,23 +16,22 @@ import com.oronaminc.join.room.dao.RoomRepository; import com.oronaminc.join.room.domain.Room; import com.oronaminc.join.room.domain.RoomStatus; -import com.oronaminc.join.room.dto.CreateRoomRequest; -import com.oronaminc.join.room.dto.CreateRoomResponse; -import com.oronaminc.join.room.dto.JoinRoomRequest; -import com.oronaminc.join.room.dto.JoinRoomResponse; -import com.oronaminc.join.room.dto.ReportResponse; +import com.oronaminc.join.room.dto.*; import com.oronaminc.join.room.event.RoomDeleteEvent; -import com.oronaminc.join.room.dto.RoomDetailResponse; -import com.oronaminc.join.room.dto.RoomJoinResponse; -import com.oronaminc.join.room.dto.RoomUpdateInfoResponse; -import com.oronaminc.join.room.dto.RoomUpdateRequest; -import com.oronaminc.join.room.dto.RoomUpdateStatusRequest; -import com.oronaminc.join.room.dto.TopQnAResponse; import com.oronaminc.join.room.util.CodeGenerator; import com.oronaminc.join.room.util.RoomMapper; import com.oronaminc.join.websocket.session.CurrentParticipantManager; - import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.oronaminc.join.global.exception.ErrorCode.*; @Service @Transactional(readOnly = true) @@ -139,7 +127,7 @@ public void deleteRoom(Long memberId, Long roomId) { @Transactional @CacheEvict(cacheNames = "roomById", key = "#roomId") public void updateRoomStatus(Long memberId, Long roomId, - RoomUpdateStatusRequest roomUpdateStatusRequest) { + RoomUpdateStatusRequest roomUpdateStatusRequest) { participantService.validatePresenter(roomId, memberId); Room room = roomReader.getById(roomId); @@ -215,9 +203,12 @@ private List getTopQnA(Long roomId) { } private Double calculateAnswerRate(Long totalQuestions, Long totalAnswerByQuestion) { - return (totalQuestions == 0) - ? 0.0 - : ((double)totalAnswerByQuestion / totalQuestions) * 100; + if (totalQuestions == 0) { + return 0.0; + } + + double rate = ((double) totalAnswerByQuestion / totalQuestions) * 100; + return Math.round(rate * 10.0) / 10.0; } diff --git a/src/test/java/com/oronaminc/join/member/service/MyPageServiceTests.java b/src/test/java/com/oronaminc/join/member/service/MyPageServiceTests.java index 7e14314..8e65792 100644 --- a/src/test/java/com/oronaminc/join/member/service/MyPageServiceTests.java +++ b/src/test/java/com/oronaminc/join/member/service/MyPageServiceTests.java @@ -1,11 +1,12 @@ package com.oronaminc.join.member.service; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.time.LocalDateTime; -import java.util.List; - +import com.oronaminc.join.member.domain.Member; +import com.oronaminc.join.member.dto.*; +import com.oronaminc.join.participant.domain.Participant; +import com.oronaminc.join.participant.domain.ParticipantType; +import com.oronaminc.join.participant.service.ParticipantReader; +import com.oronaminc.join.question.service.QuestionReader; +import com.oronaminc.join.room.domain.Room; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,18 +19,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.test.util.ReflectionTestUtils; -import com.oronaminc.join.member.domain.Member; -import com.oronaminc.join.member.dto.MyPageType; -import com.oronaminc.join.member.dto.MyProfileGetResponse; -import com.oronaminc.join.member.dto.MyProfileUpdateRequest; -import com.oronaminc.join.member.dto.MyRoomsGetResponse; -import com.oronaminc.join.member.dto.ParticipantCountDto; -import com.oronaminc.join.member.dto.ParticipationType; -import com.oronaminc.join.participant.domain.Participant; -import com.oronaminc.join.participant.domain.ParticipantType; -import com.oronaminc.join.participant.service.ParticipantReader; -import com.oronaminc.join.question.service.QuestionReader; -import com.oronaminc.join.room.domain.Room; +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class MyPageServiceTests { @@ -54,14 +48,14 @@ void getMyProfile_success_test() { Member member = Member.builder().build(); List pc = List.of( - new ParticipantCountDto(ParticipantType.PRESENTER, 1L), - new ParticipantCountDto(ParticipantType.TEAM, 1L), - new ParticipantCountDto(ParticipantType.GUEST, 1L) + new ParticipantCountDto(ParticipantType.PRESENTER, 1L), + new ParticipantCountDto(ParticipantType.TEAM, 1L), + new ParticipantCountDto(ParticipantType.GUEST, 1L) ); when(memberReader.getById(member.getId())).thenReturn(member); when(participantReader.countByMemberIdGroupByParticipantType(member.getId())) - .thenReturn(pc); + .thenReturn(pc); // when MyProfileGetResponse myProfile = myPageService.getMyProfile(member.getId()); @@ -84,7 +78,7 @@ void getMyProfile_success_test2() { when(memberReader.getById(member.getId())).thenReturn(member); when(participantReader.countByMemberIdGroupByParticipantType(member.getId())) - .thenReturn(pc); + .thenReturn(pc); // when MyProfileGetResponse myProfile = myPageService.getMyProfile(member.getId()); @@ -127,8 +121,8 @@ void getMyRooms_success_test() { Pageable pageable = PageRequest.of(0, 10); Room room1 = Room.builder() - .title("~1~의 정석") - .build(); + .title("~1~의 정석") + .build(); Room room2 = Room.builder().title("~2~의 정석").build(); Room room3 = Room.builder().title("~3~의 정석").build(); ReflectionTestUtils.setField(room1, "id", 100L); @@ -139,33 +133,35 @@ void getMyRooms_success_test() { ReflectionTestUtils.setField(room3, "createdAt", LocalDateTime.now()); Participant participant1 = Participant.builder() - .room(room1) - .member(member) - .participantType(ParticipantType.PRESENTER) - .build(); + .room(room1) + .member(member) + .participantType(ParticipantType.PRESENTER) + .build(); Participant participant2 = Participant.builder() - .room(room2) - .member(member) - .participantType(ParticipantType.TEAM) - .build(); + .room(room2) + .member(member) + .participantType(ParticipantType.TEAM) + .build(); Participant participant3 = Participant.builder() - .room(room3) - .member(member) - .participantType(ParticipantType.GUEST) - .build(); + .room(room3) + .member(member) + .participantType(ParticipantType.GUEST) + .build(); + ReflectionTestUtils.setField(participant2, "createdAt", LocalDateTime.now()); + ReflectionTestUtils.setField(participant3, "createdAt", LocalDateTime.now()); List pc = List.of(participant1, participant2, participant3); Page participantPage = new PageImpl<>(pc, pageable, 1); List roomIds = List.of(room1.getId(), room2.getId(), room3.getId()); List questions = List.of( - new Object[]{room1.getId(), 1L}, - new Object[]{room2.getId(), 2L}, - new Object[]{room3.getId(), 3L} + new Object[]{room1.getId(), 1L}, + new Object[]{room2.getId(), 2L}, + new Object[]{room3.getId(), 3L} ); when(participantReader.findByMemberId(memberId, pageable)) - .thenReturn(participantPage); + .thenReturn(participantPage); when(questionReader.countByRoomIds(roomIds)).thenReturn(questions); // when @@ -176,7 +172,7 @@ void getMyRooms_success_test() { assertThat(result.content().getFirst().roomId()).isEqualTo(100L); assertThat(result.content().getFirst().title()).isEqualTo("~1~의 정석"); assertThat(result.content().getFirst().participationType()).isEqualTo( - ParticipationType.CREATED); + ParticipationType.CREATED); assertThat(result.content().get(1).participationType()).isEqualTo(ParticipationType.JOINED); }