From 55f92582ad2688e7387515cf5dfcee06d5e63462 Mon Sep 17 00:00:00 2001 From: KyungMin Lee Date: Tue, 27 Feb 2024 10:51:56 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[FIX]=20Reissue=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=EB=B3=B4=EC=95=88=20=EC=98=B5=EC=85=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#185)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: happyjamy <78072370+happyjamy@users.noreply.github.com> --- .../io/oeid/mogakgo/core/configuration/SecurityConfig.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/oeid/mogakgo/core/configuration/SecurityConfig.java b/src/main/java/io/oeid/mogakgo/core/configuration/SecurityConfig.java index 31da7578..d268c0be 100644 --- a/src/main/java/io/oeid/mogakgo/core/configuration/SecurityConfig.java +++ b/src/main/java/io/oeid/mogakgo/core/configuration/SecurityConfig.java @@ -46,7 +46,10 @@ SecurityFilterChain filterChainApi(HttpSecurity http) throws Exception { .sessionManagement( management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests( - requests -> requests.anyRequest().authenticated()) + requests -> { + requests.requestMatchers("/api/v1/auth/**").permitAll(); + requests.anyRequest().authenticated(); + }) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .exceptionHandling(handling -> handling.accessDeniedHandler(jwtAccessDeniedHandler) From deb0ba98e5a339df02355bae80c4716effb514a2 Mon Sep 17 00:00:00 2001 From: KyungMin Lee Date: Tue, 27 Feb 2024 14:09:55 +0900 Subject: [PATCH 2/7] =?UTF-8?q?Bug/#187=20chatroom=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95=20(#188)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FIX] 채팅방 조회 오류 수정 * [FIX] 읽기 전용 트랜잭션 수정 --- .../chat/application/dto/res/ChatRoomPublicRes.java | 13 +++++++++++-- .../ChatRoomCustomRepositoryImpl.java | 10 ++++++---- .../domain/user/application/UserService.java | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomPublicRes.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomPublicRes.java index 6a80338e..6dda8cce 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomPublicRes.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomPublicRes.java @@ -5,23 +5,32 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDateTime; import java.util.List; -import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.Setter; @Schema(description = "채팅방 리스트 조회 응답") @Getter -@AllArgsConstructor public class ChatRoomPublicRes { @Schema(description = "프로젝트 ID") private Long projectId; @Schema(description = "채팅방 ID") private String chatRoomId; + @Setter @Schema(description = "마지막 메시지") private String lastMessage; + @Setter @Schema(description = "마지막 메시지 생성 시간") private LocalDateTime lastMessageCreatedAt; @Schema(description = "채팅방 상태") private ChatStatus status; private List profiles; + + public ChatRoomPublicRes(Long projectId, String chatRoomId, ChatStatus status, + List profiles) { + this.projectId = projectId; + this.chatRoomId = chatRoomId; + this.status = status; + this.profiles = profiles; + } } diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java index 02ba1299..e2311013 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java @@ -1,12 +1,12 @@ package io.oeid.mogakgo.domain.chat.infrastructure; import static io.oeid.mogakgo.domain.chat.entity.document.QChatRoom.chatRoom; -import static io.oeid.mogakgo.domain.user.domain.QUser.user; import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomPublicRes; import io.oeid.mogakgo.domain.chat.application.vo.ChatUserInfo; +import io.oeid.mogakgo.domain.user.domain.QUser; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -18,13 +18,15 @@ public class ChatRoomCustomRepositoryImpl implements ChatRoomCustomRepository { private final JPAQueryFactory jpaQueryFactory; public List findAllChatRoomByUserId(Long userId) { + + QUser sender = new QUser("sender"); + QUser creator = new QUser("creator"); + return jpaQueryFactory.select( Projections.constructor( ChatRoomPublicRes.class, chatRoom.project.id, chatRoom.id, - null, - null, chatRoom.status, Projections.list(List.of( Projections.constructor( @@ -42,7 +44,7 @@ public List findAllChatRoomByUserId(Long userId) { ) ) ) - ).from(chatRoom).join(chatRoom.creator, user).join(chatRoom.sender, user) + ).from(chatRoom).join(chatRoom.creator, creator).join(chatRoom.sender, sender) .where(chatRoom.creator.id.eq(userId).or(chatRoom.sender.id.eq(userId))) .fetch(); } diff --git a/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java b/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java index c53bc647..df51884d 100644 --- a/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java +++ b/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java @@ -82,6 +82,7 @@ public UserProfileResponse getUserProfile(Long userId) { } // TODO: 이후 AchievementException 구현 시 추가 필요! + @Transactional public UserUpdateRes updateUserInfos(Long userId, UserUpdateReq request) { User user = userCommonService.getUserById(userId); Achievement achievement = achievementRepository.findById(request.getAchievementId()) From 15814ef7d8c148993018a93363f4a34679f0bbba Mon Sep 17 00:00:00 2001 From: KyungMin Lee Date: Wed, 28 Feb 2024 10:23:45 +0900 Subject: [PATCH 3/7] =?UTF-8?q?Refact/#191=20=EC=B1=84=ED=8C=85=EB=B0=A9?= =?UTF-8?q?=20API=20=EB=B6=84=EB=A6=AC=20(#192)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [RENAME] `ChatRoom` 패키지 위치 변경 * [REFACT] 채팅방 정보 제공 API 분리 * [FEAT] Mongo DB Document에 대한 Auto Increase 적용 * [FEAT] Mongo DB Document에 대한 Cursor Pagination 적용 --- .../common/swagger/template/ChatSwagger.java | 58 ++++++++++++++----- .../ChatIdSequenceGeneratorService.java | 26 +++++++++ .../domain/chat/application/ChatService.java | 25 ++++++-- .../application/ChatWebSocketService.java | 2 +- .../res/ChatDataRes.java} | 12 ++-- .../dto/res/ChatRoomCreateRes.java | 2 +- .../application/dto/res/ChatRoomDataRes.java | 22 +++---- .../application/vo/ChatRoomProjectInfo.java | 19 ------ .../chat/entity/{document => }/ChatRoom.java | 2 +- .../chat/entity/document/ChatIdSequence.java | 15 +++++ .../chat/entity/document/ChatMessage.java | 9 ++- .../chat/handler/CustomWebSocketHandler.java | 5 +- .../chat/infrastructure/ChatRepository.java | 26 +++++++-- .../ChatRoomCustomRepositoryImpl.java | 4 +- .../ChatRoomRoomJpaRepository.java | 2 +- .../chat/presentation/ChatController.java | 18 +++++- 16 files changed, 177 insertions(+), 70 deletions(-) create mode 100644 src/main/java/io/oeid/mogakgo/domain/chat/application/ChatIdSequenceGeneratorService.java rename src/main/java/io/oeid/mogakgo/domain/chat/application/{vo/ChatData.java => dto/res/ChatDataRes.java} (65%) delete mode 100644 src/main/java/io/oeid/mogakgo/domain/chat/application/vo/ChatRoomProjectInfo.java rename src/main/java/io/oeid/mogakgo/domain/chat/entity/{document => }/ChatRoom.java (97%) create mode 100644 src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatIdSequence.java diff --git a/src/main/java/io/oeid/mogakgo/common/swagger/template/ChatSwagger.java b/src/main/java/io/oeid/mogakgo/common/swagger/template/ChatSwagger.java index e418e484..14c18345 100644 --- a/src/main/java/io/oeid/mogakgo/common/swagger/template/ChatSwagger.java +++ b/src/main/java/io/oeid/mogakgo/common/swagger/template/ChatSwagger.java @@ -2,14 +2,18 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import io.oeid.mogakgo.common.base.CursorPaginationInfoReq; +import io.oeid.mogakgo.common.base.CursorPaginationResult; import io.oeid.mogakgo.core.properties.swagger.error.SwaggerChatErrorExamples; import io.oeid.mogakgo.core.properties.swagger.error.SwaggerProjectErrorExamples; import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples; +import io.oeid.mogakgo.domain.chat.application.dto.res.ChatDataRes; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomDataRes; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomPublicRes; import io.oeid.mogakgo.exception.dto.ErrorResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; @@ -28,11 +32,11 @@ public interface ChatSwagger { @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "채팅방 목록 조회 성공"), @ApiResponse(responseCode = "404", description = "요청한 유저가 존재하지 않음", - content = @Content( - mediaType = APPLICATION_JSON_VALUE, - schema = @Schema(implementation = ErrorResponse.class), - examples = @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND) - )) + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorResponse.class), + examples = @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND) + )) }) ResponseEntity> getChatRoomList(@Parameter(hidden = true) Long userId); @@ -40,16 +44,40 @@ public interface ChatSwagger { @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "채팅방 상세 조회 성공"), @ApiResponse(responseCode = "404", description = "요청한 데이터가 유효하지 않음", - content = @Content( - mediaType = APPLICATION_JSON_VALUE, - schema = @Schema(implementation = ErrorResponse.class), - examples = { - @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND), - @ExampleObject(name = "E030301", value = SwaggerProjectErrorExamples.PROJECT_NOT_FOUND), - @ExampleObject(name = "E110301", value = SwaggerChatErrorExamples.CHAT_ROOM_NOT_FOUND) - } - )) + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorResponse.class), + examples = { + @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND), + @ExampleObject(name = "E030301", value = SwaggerProjectErrorExamples.PROJECT_NOT_FOUND), + @ExampleObject(name = "E110301", value = SwaggerChatErrorExamples.CHAT_ROOM_NOT_FOUND) + } + )) }) - ResponseEntity getChatRoomDetailData(@Parameter(hidden = true) Long userId, + ResponseEntity getChatRoomDetailData( + @Parameter(hidden = true) Long userId, @Parameter(in = ParameterIn.PATH) String chatRoomId); + + @Operation(summary = "채팅 내용 조회", description = "채팅방의 채팅 내용을 조회하는 API") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "채팅 내용 조회 성공"), + @ApiResponse(responseCode = "404", description = "요청한 데이터가 유효하지 않음", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorResponse.class), + examples = { + @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND), + @ExampleObject(name = "E110301", value = SwaggerChatErrorExamples.CHAT_ROOM_NOT_FOUND) + } + )) + }) + @Parameters({ + @Parameter(name = "cursorId", description = "기준이 되는 커서 ID", example = "1"), + @Parameter(name = "pageSize", description = "요청할 데이터 크기", example = "5", required = true), + @Parameter(name = "sortOrder", description = "정렬 방향", example = "ASC"), + }) + ResponseEntity> getChatData( + @Parameter(in = ParameterIn.PATH) String chatRoomId, + @Parameter(hidden = true) Long userId, + @Parameter(hidden = true) CursorPaginationInfoReq pageable); } diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatIdSequenceGeneratorService.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatIdSequenceGeneratorService.java new file mode 100644 index 00000000..2914e089 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatIdSequenceGeneratorService.java @@ -0,0 +1,26 @@ +package io.oeid.mogakgo.domain.chat.application; + +import static org.springframework.data.mongodb.core.FindAndModifyOptions.options; +import static org.springframework.data.mongodb.core.query.Criteria.where; +import static org.springframework.data.mongodb.core.query.Query.query; + +import io.oeid.mogakgo.domain.chat.entity.document.ChatIdSequence; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ChatIdSequenceGeneratorService { + + private final MongoOperations mongoOperations; + + public Long generateSequence(String collectionName) { + ChatIdSequence counter = mongoOperations.findAndModify( + query(where("_id").is(collectionName)), new Update().inc("seq", 1), + options().returnNew(true).upsert(true), ChatIdSequence.class); + return !Objects.isNull(counter) ? counter.getSeq() : 1; + } +} diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatService.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatService.java index 19ca7d41..d5b4fc9f 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatService.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatService.java @@ -1,10 +1,13 @@ package io.oeid.mogakgo.domain.chat.application; +import io.oeid.mogakgo.common.base.CursorPaginationInfoReq; +import io.oeid.mogakgo.common.base.CursorPaginationResult; import io.oeid.mogakgo.domain.chat.application.dto.req.ChatRoomCreateReq; +import io.oeid.mogakgo.domain.chat.application.dto.res.ChatDataRes; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomCreateRes; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomDataRes; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomPublicRes; -import io.oeid.mogakgo.domain.chat.entity.document.ChatRoom; +import io.oeid.mogakgo.domain.chat.entity.ChatRoom; import io.oeid.mogakgo.domain.chat.infrastructure.ChatRepository; import io.oeid.mogakgo.domain.chat.infrastructure.ChatRoomRoomJpaRepository; import io.oeid.mogakgo.domain.matching.exception.MatchingException; @@ -52,14 +55,24 @@ public ChatRoomCreateRes createChatRoom(Long creatorId, ChatRoomCreateReq reques } // 채팅방 조회 - public ChatRoomDataRes findAllChatInChatRoom(Long userId, String chatRoomId) { + public CursorPaginationResult findAllChatInChatRoom(Long userId, String chatRoomId, CursorPaginationInfoReq pageable) { var user = userCommonService.getUserById(userId); - var chatRoom = chatRoomRepository.findById(chatRoomId) - .orElseThrow(() -> new MatchingException(ErrorCode404.CHAT_ROOM_NOT_FOUND)); + var chatRoom = findChatRoomById(chatRoomId); + chatRoom.validateContainsUser(user); + return chatRepository.findAllByCollection(chatRoomId, pageable); + } + + public ChatRoomDataRes findChatRoomDetailData(Long userId, String chatRoomId) { + var user = userCommonService.getUserById(userId); + var chatRoom = findChatRoomById(chatRoomId); chatRoom.validateContainsUser(user); var project = projectRepository.findById(chatRoom.getProject().getId()) .orElseThrow(() -> new ProjectException(ErrorCode404.PROJECT_NOT_FOUND)); - var chatList = chatRepository.findAllByCollection(chatRoomId); - return ChatRoomDataRes.of(project.getMeetingInfo(), chatList); + return ChatRoomDataRes.from(project.getMeetingInfo()); + } + + private ChatRoom findChatRoomById(String chatRoomId) { + return chatRoomRepository.findById(chatRoomId) + .orElseThrow(() -> new MatchingException(ErrorCode404.CHAT_ROOM_NOT_FOUND)); } } diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatWebSocketService.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatWebSocketService.java index 5082dabd..7d5570ee 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatWebSocketService.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/application/ChatWebSocketService.java @@ -3,8 +3,8 @@ import static io.oeid.mogakgo.exception.code.ErrorCode500.CHAT_WEB_SOCKET_ERROR; +import io.oeid.mogakgo.domain.chat.entity.ChatRoom; import io.oeid.mogakgo.domain.chat.entity.document.ChatMessage; -import io.oeid.mogakgo.domain.chat.entity.document.ChatRoom; import io.oeid.mogakgo.domain.chat.entity.enums.ChatStatus; import io.oeid.mogakgo.domain.chat.exception.ChatException; import io.oeid.mogakgo.domain.chat.infrastructure.ChatRepository; diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/vo/ChatData.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatDataRes.java similarity index 65% rename from src/main/java/io/oeid/mogakgo/domain/chat/application/vo/ChatData.java rename to src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatDataRes.java index cdd0b1c3..fede07d8 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/application/vo/ChatData.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatDataRes.java @@ -1,4 +1,4 @@ -package io.oeid.mogakgo.domain.chat.application.vo; +package io.oeid.mogakgo.domain.chat.application.dto.res; import io.oeid.mogakgo.domain.chat.entity.document.ChatMessage; import io.oeid.mogakgo.domain.chat.entity.enums.ChatMessageType; @@ -11,8 +11,10 @@ @Schema(description = "채팅 데이터") @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) -public class ChatData { +public class ChatDataRes { + @Schema(description = "채팅 ID") + private Long id; @Schema(description = "메시지 타입") private ChatMessageType messageType; @Schema(description = "보낸 사람 ID") @@ -22,8 +24,8 @@ public class ChatData { @Schema(description = "생성 시간") private LocalDateTime createdAt; - public static ChatData from(ChatMessage chatMessage) { - return new ChatData(chatMessage.getMessageType(), chatMessage.getSenderId(), - chatMessage.getMessage(), chatMessage.getCreatedAt()); + public static ChatDataRes from(ChatMessage chatMessage) { + return new ChatDataRes(chatMessage.getId(), chatMessage.getMessageType(), + chatMessage.getSenderId(), chatMessage.getMessage(), chatMessage.getCreatedAt()); } } diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomCreateRes.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomCreateRes.java index 7faa2598..a59a0325 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomCreateRes.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomCreateRes.java @@ -1,6 +1,6 @@ package io.oeid.mogakgo.domain.chat.application.dto.res; -import io.oeid.mogakgo.domain.chat.entity.document.ChatRoom; +import io.oeid.mogakgo.domain.chat.entity.ChatRoom; import io.oeid.mogakgo.domain.chat.entity.enums.ChatStatus; import lombok.Getter; diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomDataRes.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomDataRes.java index 978d10fa..1074fa6f 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomDataRes.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/application/dto/res/ChatRoomDataRes.java @@ -1,28 +1,28 @@ package io.oeid.mogakgo.domain.chat.application.dto.res; -import io.oeid.mogakgo.domain.chat.application.vo.ChatData; -import io.oeid.mogakgo.domain.chat.application.vo.ChatRoomProjectInfo; -import io.oeid.mogakgo.domain.chat.entity.document.ChatMessage; import io.oeid.mogakgo.domain.project.domain.entity.vo.MeetingInfo; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; +import java.time.LocalDateTime; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -@Schema(description = "채팅방 데이터 조회 응답") +@Schema(description = "채팅방 프로젝트 정보") @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor public class ChatRoomDataRes { - private ChatRoomProjectInfo project; - private List data; + @Schema(description = "프로젝트 설명") + private String meetDetail; + @Schema(description = "프로젝트 시작 시간") + private LocalDateTime meetStartTime; + @Schema(description = "프로젝트 종료 시간") + private LocalDateTime meetEndTime; - public static ChatRoomDataRes of(MeetingInfo meetingInfo, List data) { - ChatRoomProjectInfo project = new ChatRoomProjectInfo(meetingInfo.getMeetDetail(), - meetingInfo.getMeetStartTime(), meetingInfo.getMeetEndTime()); - return new ChatRoomDataRes(project, data.stream().map(ChatData::from).toList()); + public static ChatRoomDataRes from(MeetingInfo meetingInfo) { + return new ChatRoomDataRes(meetingInfo.getMeetDetail(), meetingInfo.getMeetStartTime(), + meetingInfo.getMeetEndTime()); } } diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/application/vo/ChatRoomProjectInfo.java b/src/main/java/io/oeid/mogakgo/domain/chat/application/vo/ChatRoomProjectInfo.java deleted file mode 100644 index ad285193..00000000 --- a/src/main/java/io/oeid/mogakgo/domain/chat/application/vo/ChatRoomProjectInfo.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.oeid.mogakgo.domain.chat.application.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.LocalDateTime; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Schema(description = "채팅방 프로젝트 정보") -@Getter -@AllArgsConstructor -public class ChatRoomProjectInfo { - - @Schema(description = "프로젝트 설명") - private String meetDetail; - @Schema(description = "프로젝트 시작 시간") - private LocalDateTime meetStartTime; - @Schema(description = "프로젝트 종료 시간") - private LocalDateTime meetEndTime; -} diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatRoom.java b/src/main/java/io/oeid/mogakgo/domain/chat/entity/ChatRoom.java similarity index 97% rename from src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatRoom.java rename to src/main/java/io/oeid/mogakgo/domain/chat/entity/ChatRoom.java index d661d1be..25b1e12d 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatRoom.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/entity/ChatRoom.java @@ -1,4 +1,4 @@ -package io.oeid.mogakgo.domain.chat.entity.document; +package io.oeid.mogakgo.domain.chat.entity; import io.oeid.mogakgo.domain.chat.entity.enums.ChatStatus; import io.oeid.mogakgo.domain.chat.exception.ChatException; diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatIdSequence.java b/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatIdSequence.java new file mode 100644 index 00000000..15e154b0 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatIdSequence.java @@ -0,0 +1,15 @@ +package io.oeid.mogakgo.domain.chat.entity.document; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Setter +@Getter +@Document(collection = "chat_sequence") +public class ChatIdSequence { + @Id + private String id; + private Long seq; +} diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatMessage.java b/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatMessage.java index 657ca5ff..8ab2ca9a 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatMessage.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/entity/document/ChatMessage.java @@ -3,17 +3,22 @@ import io.oeid.mogakgo.domain.chat.entity.enums.ChatMessageType; import java.time.LocalDateTime; import lombok.Getter; +import lombok.Setter; +import org.springframework.data.mongodb.core.mapping.Document; @Getter +@Document public class ChatMessage { - + @Setter + private Long id; private ChatMessageType messageType; private String chatRoomId; private Long senderId; private String message; private LocalDateTime createdAt; - public ChatMessage(ChatMessageType messageType, String chatRoomId, Long senderId, String message) { + public ChatMessage(ChatMessageType messageType, String chatRoomId, Long senderId, + String message) { this.messageType = messageType; this.chatRoomId = chatRoomId; this.senderId = senderId; diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/handler/CustomWebSocketHandler.java b/src/main/java/io/oeid/mogakgo/domain/chat/handler/CustomWebSocketHandler.java index c6b4e579..7eb976a6 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/handler/CustomWebSocketHandler.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/handler/CustomWebSocketHandler.java @@ -3,9 +3,10 @@ import static io.oeid.mogakgo.exception.code.ErrorCode500.CHAT_WEB_SOCKET_ERROR; import com.fasterxml.jackson.databind.ObjectMapper; +import io.oeid.mogakgo.domain.chat.application.ChatIdSequenceGeneratorService; import io.oeid.mogakgo.domain.chat.application.ChatWebSocketService; +import io.oeid.mogakgo.domain.chat.entity.ChatRoom; import io.oeid.mogakgo.domain.chat.entity.document.ChatMessage; -import io.oeid.mogakgo.domain.chat.entity.document.ChatRoom; import io.oeid.mogakgo.domain.chat.exception.ChatException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,6 +24,7 @@ public class CustomWebSocketHandler implements WebSocketHandler { private final ObjectMapper objectMapper; private final ChatWebSocketService chatWebSocketService; + private final ChatIdSequenceGeneratorService sequenceGeneratorService; @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { @@ -44,6 +46,7 @@ public void handleMessage(WebSocketSession session, WebSocketMessage message) } default -> chatWebSocketService.sendMessageToEachSocket(chatRoom.getId(), textMessage); } + chatMessage.setId(sequenceGeneratorService.generateSequence(chatMessage.getChatRoomId())); chatWebSocketService.saveChatMessage(chatMessage, chatRoom.getId()); } diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRepository.java b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRepository.java index 50a5b616..0f2bd131 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRepository.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRepository.java @@ -1,10 +1,13 @@ package io.oeid.mogakgo.domain.chat.infrastructure; +import io.oeid.mogakgo.common.base.CursorPaginationInfoReq; +import io.oeid.mogakgo.common.base.CursorPaginationResult; +import io.oeid.mogakgo.domain.chat.application.dto.res.ChatDataRes; import io.oeid.mogakgo.domain.chat.entity.document.ChatMessage; -import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Repository; @@ -24,9 +27,24 @@ public ChatMessage save(ChatMessage chatMessage, String collectionName) { return mongoTemplate.save(chatMessage, collectionName); } - public List findAllByCollection(String collectionName) { + public CursorPaginationResult findAllByCollection(String collectionName, + CursorPaginationInfoReq pageable) { Query query = new Query(); - query.with(Sort.by(Sort.Order.desc("createdAt"))); - return mongoTemplate.find(query, ChatMessage.class, collectionName); + query.limit(pageable.getPageSize()).addCriteria(cursorIdCondition(pageable.getCursorId())) + .with(Sort.by(Sort.Order.desc("createdAt"))); + var result = mongoTemplate.find(query, ChatMessage.class, collectionName).stream() + .map(ChatDataRes::from).toList(); + return CursorPaginationResult.fromDataWithHasNext(result, pageable.getPageSize(), + hasNext(pageable.getCursorId(), pageable.getPageSize(), collectionName)); + } + + private Criteria cursorIdCondition(Long cursorId) { + return cursorId != null ? Criteria.where("id").lt(cursorId) : Criteria.where("id").gt(0L); + } + + private boolean hasNext(Long cursorId, int pageSize, String collectionName) { + return cursorId == null ? mongoTemplate.estimatedCount(collectionName) > pageSize + : mongoTemplate.count(new Query(Criteria.where("id").lt(cursorId)), ChatMessage.class, + collectionName) > pageSize; } } diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java index e2311013..c6ebd618 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomCustomRepositoryImpl.java @@ -1,6 +1,8 @@ package io.oeid.mogakgo.domain.chat.infrastructure; -import static io.oeid.mogakgo.domain.chat.entity.document.QChatRoom.chatRoom; + + +import static io.oeid.mogakgo.domain.chat.entity.QChatRoom.chatRoom; import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomRoomJpaRepository.java b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomRoomJpaRepository.java index e11a1e61..4ed03099 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomRoomJpaRepository.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/infrastructure/ChatRoomRoomJpaRepository.java @@ -1,6 +1,6 @@ package io.oeid.mogakgo.domain.chat.infrastructure; -import io.oeid.mogakgo.domain.chat.entity.document.ChatRoom; +import io.oeid.mogakgo.domain.chat.entity.ChatRoom; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/src/main/java/io/oeid/mogakgo/domain/chat/presentation/ChatController.java b/src/main/java/io/oeid/mogakgo/domain/chat/presentation/ChatController.java index 3803eadc..e916f352 100644 --- a/src/main/java/io/oeid/mogakgo/domain/chat/presentation/ChatController.java +++ b/src/main/java/io/oeid/mogakgo/domain/chat/presentation/ChatController.java @@ -1,18 +1,25 @@ package io.oeid.mogakgo.domain.chat.presentation; import io.oeid.mogakgo.common.annotation.UserId; +import io.oeid.mogakgo.common.base.CursorPaginationInfoReq; +import io.oeid.mogakgo.common.base.CursorPaginationResult; import io.oeid.mogakgo.common.swagger.template.ChatSwagger; import io.oeid.mogakgo.domain.chat.application.ChatService; +import io.oeid.mogakgo.domain.chat.application.dto.res.ChatDataRes; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomDataRes; import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomPublicRes; +import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; + +// TODO: FIX SWAGGER @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/chat") @@ -25,9 +32,16 @@ public ResponseEntity> getChatRoomList(@UserId Long user return ResponseEntity.ok(chatService.findAllChatRoomByUserId(userId)); } - @GetMapping("/{chatRoomId}") + @GetMapping("detail/{chatRoomId}") public ResponseEntity getChatRoomDetailData(@UserId Long userId, @PathVariable String chatRoomId) { - return ResponseEntity.ok(chatService.findAllChatInChatRoom(userId, chatRoomId)); + return ResponseEntity.ok(chatService.findChatRoomDetailData(userId, chatRoomId)); + } + + @GetMapping("/{chatRoomId}") + public ResponseEntity> getChatData( + @PathVariable String chatRoomId, + @UserId Long userId, @Valid @ModelAttribute CursorPaginationInfoReq pageable) { + return ResponseEntity.ok(chatService.findAllChatInChatRoom(userId, chatRoomId, pageable)); } } From b5fdf119fcc526e583c2de45cc29b229f7ea3ccc Mon Sep 17 00:00:00 2001 From: happyjamy <78072370+happyjamy@users.noreply.github.com> Date: Wed, 28 Feb 2024 13:57:17 +0900 Subject: [PATCH 4/7] =?UTF-8?q?Feat/#182=20=EC=97=85=EC=A0=81=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B5=AC=ED=98=84=20(#189)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [RENAME] entity 안으로 폴더 이동 * [FEAT] 업적 도메인 구현 * [STYLE] 카멜케이스 적용 --- .../domain/{ => entity}/Achievement.java | 30 ++++++----- .../domain/entity/UserAchievement.java | 51 +++++++++++++++++++ .../domain/entity/UserActivity.java | 48 +++++++++++++++++ .../domain/entity/enums/ActivityType.java | 31 +++++++++++ .../domain/entity/enums/RequirementType.java | 8 +++ .../domain/enums/AchievementType.java | 6 --- .../AchievementJpaRepository.java | 4 +- .../domain/user/application/UserService.java | 2 +- .../oeid/mogakgo/domain/user/domain/User.java | 2 +- 9 files changed, 158 insertions(+), 24 deletions(-) rename src/main/java/io/oeid/mogakgo/domain/achievement/domain/{ => entity}/Achievement.java (59%) create mode 100644 src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserAchievement.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserActivity.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/ActivityType.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/RequirementType.java delete mode 100644 src/main/java/io/oeid/mogakgo/domain/achievement/domain/enums/AchievementType.java diff --git a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/Achievement.java b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/Achievement.java similarity index 59% rename from src/main/java/io/oeid/mogakgo/domain/achievement/domain/Achievement.java rename to src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/Achievement.java index 6052841c..16ea0038 100644 --- a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/Achievement.java +++ b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/Achievement.java @@ -1,6 +1,7 @@ -package io.oeid.mogakgo.domain.achievement.domain; +package io.oeid.mogakgo.domain.achievement.domain.entity; -import io.oeid.mogakgo.domain.achievement.domain.enums.AchievementType; +import io.oeid.mogakgo.domain.achievement.domain.entity.enums.ActivityType; +import io.oeid.mogakgo.domain.achievement.domain.entity.enums.RequirementType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -9,7 +10,6 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -33,16 +33,18 @@ public class Achievement { @Column(name = "img_url") private String imgUrl; + @Column(name = "progress_level") + private Integer progressLevel; + @Enumerated(EnumType.STRING) - @Column(name = "type") - private AchievementType achievementType; - - @Builder - private Achievement(String title, String description, String imgUrl, - AchievementType achievementType) { - this.title = title; - this.description = description; - this.imgUrl = imgUrl; - this.achievementType = achievementType; - } + @Column(name = "requirement_type") + private RequirementType requirementType; + + @Column(name = "requirement_value") + private Integer requirementValue; + + @Enumerated(EnumType.STRING) + @Column(name = "activity_type") + private ActivityType activityType; + } diff --git a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserAchievement.java b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserAchievement.java new file mode 100644 index 00000000..d0053180 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserAchievement.java @@ -0,0 +1,51 @@ +package io.oeid.mogakgo.domain.achievement.domain.entity; + +import io.oeid.mogakgo.domain.user.domain.User; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Getter +@Entity +@Table(name = "user_achievement_tb") +@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) +@EntityListeners(AuditingEntityListener.class) +public class UserAchievement { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "achievement_id") + private Achievement achievement; + + // TODO: 필요하면 개발하다가 추가 +// @Column(name = "progress_count") +// private Integer progressCount; + + @Column(name = "completed") + private Boolean completed; + + @CreatedDate + @Column(name = "created_at") + private LocalDateTime createdAt; + +} diff --git a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserActivity.java b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserActivity.java new file mode 100644 index 00000000..b5d1aa66 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/UserActivity.java @@ -0,0 +1,48 @@ +package io.oeid.mogakgo.domain.achievement.domain.entity; + +import io.oeid.mogakgo.domain.achievement.domain.entity.enums.ActivityType; +import io.oeid.mogakgo.domain.user.domain.User; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Getter +@Entity +@Table(name = "user_activity_tb") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@EntityListeners(AuditingEntityListener.class) +public class UserActivity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @Enumerated(EnumType.STRING) + @Column(name = "activity_type") + private ActivityType activityType; + + @CreatedDate + @Column(name = "created_at") + private LocalDateTime createdAt; + +} diff --git a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/ActivityType.java b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/ActivityType.java new file mode 100644 index 00000000..94eef4de --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/ActivityType.java @@ -0,0 +1,31 @@ +package io.oeid.mogakgo.domain.achievement.domain.entity.enums; + +import java.util.List; +import lombok.Getter; + +@Getter +public enum ActivityType { + + FROM_ONE_STEP(List.of(2, 3, 4)), + GOOD_PERSON_GOOD_MEETUP(List.of(5, 6, 7)), + LIKE_E(List.of(8, 9, 10)), + MY_DESTINY(List.of(11)), + CAPTURE_FAIL_EXIST(List.of(12)), + RUN_AWAY_FROM_MONSTAR_BALL(List.of(13)), + PLEASE_GIVE_ME_MOGAK(List.of(14, 15, 16)), + BRAVE_EXPLORER(List.of(17)), + NOMAD_CODER(List.of(18)), + CATCH_ME_IF_YOU_CAN(List.of(19, 20, 21)), + LEAVE_YOUR_MARK(List.of(22)), + WHAT_A_POPULAR_PERSON(List.of(23, 24, 25)), + CONTACT_WITH_GOD(List.of(26)), + FRESH_DEVELOPER(List.of(28, 29, 30)), + ; + + private final List includedDbIdList; + + ActivityType(List includedDbIdList) { + this.includedDbIdList = includedDbIdList; + } + +} diff --git a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/RequirementType.java b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/RequirementType.java new file mode 100644 index 00000000..ee757b34 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/entity/enums/RequirementType.java @@ -0,0 +1,8 @@ +package io.oeid.mogakgo.domain.achievement.domain.entity.enums; + +public enum RequirementType { + SEQUENCE, + ACCUMULATE, + ; + +} diff --git a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/enums/AchievementType.java b/src/main/java/io/oeid/mogakgo/domain/achievement/domain/enums/AchievementType.java deleted file mode 100644 index 3f2faaad..00000000 --- a/src/main/java/io/oeid/mogakgo/domain/achievement/domain/enums/AchievementType.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.oeid.mogakgo.domain.achievement.domain.enums; - -public enum AchievementType { - ONCE - -} diff --git a/src/main/java/io/oeid/mogakgo/domain/achievement/infrastructure/AchievementJpaRepository.java b/src/main/java/io/oeid/mogakgo/domain/achievement/infrastructure/AchievementJpaRepository.java index cac992d4..8b1f5e56 100644 --- a/src/main/java/io/oeid/mogakgo/domain/achievement/infrastructure/AchievementJpaRepository.java +++ b/src/main/java/io/oeid/mogakgo/domain/achievement/infrastructure/AchievementJpaRepository.java @@ -1,10 +1,10 @@ package io.oeid.mogakgo.domain.achievement.infrastructure; -import io.oeid.mogakgo.domain.achievement.domain.Achievement; +import io.oeid.mogakgo.domain.achievement.domain.entity.Achievement; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface AchievementJpaRepository extends JpaRepository { -} \ No newline at end of file +} diff --git a/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java b/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java index df51884d..39e12c42 100644 --- a/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java +++ b/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java @@ -1,6 +1,6 @@ package io.oeid.mogakgo.domain.user.application; -import io.oeid.mogakgo.domain.achievement.domain.Achievement; +import io.oeid.mogakgo.domain.achievement.domain.entity.Achievement; import io.oeid.mogakgo.domain.achievement.infrastructure.AchievementJpaRepository; import io.oeid.mogakgo.domain.profile.application.ProfileCardService; import io.oeid.mogakgo.domain.profile.application.dto.req.UserProfileCardReq; diff --git a/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java b/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java index 029b54d6..79503dbe 100644 --- a/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java +++ b/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java @@ -3,7 +3,7 @@ import static io.oeid.mogakgo.exception.code.ErrorCode400.USER_AVAILABLE_LIKE_AMOUNT_IS_FULL; import static io.oeid.mogakgo.exception.code.ErrorCode400.USER_AVAILABLE_LIKE_COUNT_IS_ZERO; -import io.oeid.mogakgo.domain.achievement.domain.Achievement; +import io.oeid.mogakgo.domain.achievement.domain.entity.Achievement; import io.oeid.mogakgo.domain.geo.domain.enums.Region; import io.oeid.mogakgo.domain.user.domain.enums.Role; import io.oeid.mogakgo.domain.user.exception.UserException; From 75cb83a099760ee43676e7831c207b135550db6a Mon Sep 17 00:00:00 2001 From: KyungMin Lee Date: Wed, 28 Feb 2024 14:16:17 +0900 Subject: [PATCH 5/7] =?UTF-8?q?Feat/#141=20=EB=A6=AC=EB=B7=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#190)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FEAT] Review 도메인 구현 * [FEAT] Review Exception 구현 * [FEAT] Review Repository 구현 * [FEAT] Review 생성 서비스 기능 구현 * [FEAT] 잔디력 증감 알고리즘 구현 * [FIX] 메소드명 변경에 따른 빌드 실패 오류 수정 * [RENAME] 잔디력 로직 생성에 따른 기본 값 변경 --- .../domain/project/domain/entity/Project.java | 2 +- .../review/application/ReviewService.java | 56 +++++++++++++ .../application/dto/req/ReviewCreateReq.java | 14 ++++ .../application/dto/res/ReviewCreateRes.java | 30 +++++++ .../mogakgo/domain/review/domain/Review.java | 81 +++++++++++++++++++ .../review/domain/enums/ReviewRating.java | 18 +++++ .../review/exception/ReviewException.java | 11 +++ .../infrastructure/ReviewJpaRepository.java | 14 ++++ .../oeid/mogakgo/domain/user/domain/User.java | 27 ++++--- .../mogakgo/exception/code/ErrorCode400.java | 5 ++ 10 files changed, 247 insertions(+), 11 deletions(-) create mode 100644 src/main/java/io/oeid/mogakgo/domain/review/application/ReviewService.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/review/application/dto/req/ReviewCreateReq.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/review/application/dto/res/ReviewCreateRes.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/review/domain/Review.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/review/domain/enums/ReviewRating.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/review/exception/ReviewException.java create mode 100644 src/main/java/io/oeid/mogakgo/domain/review/infrastructure/ReviewJpaRepository.java diff --git a/src/main/java/io/oeid/mogakgo/domain/project/domain/entity/Project.java b/src/main/java/io/oeid/mogakgo/domain/project/domain/entity/Project.java index 0fa3b11e..f940fc51 100644 --- a/src/main/java/io/oeid/mogakgo/domain/project/domain/entity/Project.java +++ b/src/main/java/io/oeid/mogakgo/domain/project/domain/entity/Project.java @@ -101,7 +101,7 @@ public void cancel(User tokenUser, boolean projectHasReq) { validateAvailableCancel(tokenUser); // 매칭 준비중이지만 요청이 있을때는 잔디력 감소 if (projectHasReq) { - this.creator.decreaseJandiRate(); + this.creator.updateJandiRateByCancel(); } this.projectStatus = ProjectStatus.CANCELED; } diff --git a/src/main/java/io/oeid/mogakgo/domain/review/application/ReviewService.java b/src/main/java/io/oeid/mogakgo/domain/review/application/ReviewService.java new file mode 100644 index 00000000..48e1ab90 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/review/application/ReviewService.java @@ -0,0 +1,56 @@ +package io.oeid.mogakgo.domain.review.application; + +import io.oeid.mogakgo.domain.project.infrastructure.ProjectJpaRepository; +import io.oeid.mogakgo.domain.review.application.dto.req.ReviewCreateReq; +import io.oeid.mogakgo.domain.review.application.dto.res.ReviewCreateRes; +import io.oeid.mogakgo.domain.review.domain.Review; +import io.oeid.mogakgo.domain.review.exception.ReviewException; +import io.oeid.mogakgo.domain.review.infrastructure.ReviewJpaRepository; +import io.oeid.mogakgo.domain.user.application.UserCommonService; +import io.oeid.mogakgo.exception.code.ErrorCode400; +import io.oeid.mogakgo.exception.code.ErrorCode404; +import java.time.Duration; +import java.time.LocalDateTime; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class ReviewService { + + private final ReviewJpaRepository reviewRepository; + private final ProjectJpaRepository projectRepository; + private final UserCommonService userCommonService; + + @Transactional + public ReviewCreateRes createNewReview(ReviewCreateReq request) { + reviewRepository.findReviewByProjectData(request.getSenderId(), request.getReceiverId(), + request.getProjectId()).ifPresent(review -> { + throw new ReviewException(ErrorCode400.REVIEW_ALREADY_EXISTS); + }); + var sender = userCommonService.getUserById(request.getSenderId()); + var receiver = userCommonService.getUserById(request.getReceiverId()); + var project = projectRepository.findById(request.getProjectId()) + .orElseThrow(() -> new ReviewException(ErrorCode404.PROJECT_NOT_FOUND)); + var review = reviewRepository.save(Review.builder() + .sender(sender) + .receiver(receiver) + .project(project) + .rating(request.getRating()) + .build() + ); + receiver.updateJandiRateByReview(review.getRating(), + calculateProjectTime(project.getMeetingInfo().getMeetStartTime(), + project.getMeetingInfo().getMeetEndTime())); + return ReviewCreateRes.from(review); + } + + private double calculateProjectTime(LocalDateTime meetStartTime, LocalDateTime meetEndTime) { + Duration duration = Duration.between(meetStartTime, meetEndTime); + double hours = duration.toHours(); + double minutes = duration.toMinutes() % 60; + return hours + minutes / 60; + } + +} diff --git a/src/main/java/io/oeid/mogakgo/domain/review/application/dto/req/ReviewCreateReq.java b/src/main/java/io/oeid/mogakgo/domain/review/application/dto/req/ReviewCreateReq.java new file mode 100644 index 00000000..2aa0ba1f --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/review/application/dto/req/ReviewCreateReq.java @@ -0,0 +1,14 @@ +package io.oeid.mogakgo.domain.review.application.dto.req; + +import io.oeid.mogakgo.domain.review.domain.enums.ReviewRating; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ReviewCreateReq { + private Long senderId; + private Long receiverId; + private Long projectId; + private ReviewRating rating; +} diff --git a/src/main/java/io/oeid/mogakgo/domain/review/application/dto/res/ReviewCreateRes.java b/src/main/java/io/oeid/mogakgo/domain/review/application/dto/res/ReviewCreateRes.java new file mode 100644 index 00000000..6f14a1e9 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/review/application/dto/res/ReviewCreateRes.java @@ -0,0 +1,30 @@ +package io.oeid.mogakgo.domain.review.application.dto.res; + +import io.oeid.mogakgo.domain.review.domain.Review; +import io.oeid.mogakgo.domain.review.domain.enums.ReviewRating; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class ReviewCreateRes { + private Long id; + private Long senderId; + private Long receiverId; + private Long projectId; + private ReviewRating rating; + private LocalDateTime createdAt; + + public static ReviewCreateRes from(Review review) { + return new ReviewCreateRes( + review.getId(), + review.getSender().getId(), + review.getReceiver().getId(), + review.getProject().getId(), + review.getRating(), + review.getCreatedAt() + ); + } +} diff --git a/src/main/java/io/oeid/mogakgo/domain/review/domain/Review.java b/src/main/java/io/oeid/mogakgo/domain/review/domain/Review.java new file mode 100644 index 00000000..7c9d9719 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/review/domain/Review.java @@ -0,0 +1,81 @@ +package io.oeid.mogakgo.domain.review.domain; + +import static jakarta.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PROTECTED; + +import io.oeid.mogakgo.domain.project.domain.entity.Project; +import io.oeid.mogakgo.domain.review.domain.enums.ReviewRating; +import io.oeid.mogakgo.domain.review.exception.ReviewException; +import io.oeid.mogakgo.domain.user.domain.User; +import io.oeid.mogakgo.exception.code.ErrorCode400; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.CreationTimestamp; + +@Getter +@Entity +@Table(name = "review_tb") +@NoArgsConstructor(access = PROTECTED) +public class Review { + + @Id + @GeneratedValue(strategy = IDENTITY) + @Column(name = "id") + private Long id; + + @ManyToOne + @JoinColumn(name = "sender_id") + private User sender; + + @ManyToOne + @JoinColumn(name = "receiver_id") + private User receiver; + + @ManyToOne + @JoinColumn(name = "project_id") + private Project project; + + @Enumerated(EnumType.STRING) + @Column(name = "rating") + private ReviewRating rating; + + @CreationTimestamp + @Column(name = "created_at") + LocalDateTime createdAt; + + @Builder + private Review(User sender, User receiver, Project project, ReviewRating rating) { + validateUsers(sender, receiver); + this.sender = sender; + this.receiver = receiver; + this.project = validateProject(project); + this.rating = rating; + } + + private void validateUsers(User sender, User receiver) { + if (sender == null || receiver == null) { + throw new ReviewException(ErrorCode400.REVIEW_SENDER_OR_RECEIVER_NOT_FOUND); + } + if (sender.getId().equals(receiver.getId())) { + throw new ReviewException(ErrorCode400.REVIEW_USER_DUPLICATED); + } + } + + private Project validateProject(Project project) { + if (project == null) { + throw new ReviewException(ErrorCode400.REVIEW_PROJECT_NOT_NULL); + } + return project; + } +} diff --git a/src/main/java/io/oeid/mogakgo/domain/review/domain/enums/ReviewRating.java b/src/main/java/io/oeid/mogakgo/domain/review/domain/enums/ReviewRating.java new file mode 100644 index 00000000..29deeb42 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/review/domain/enums/ReviewRating.java @@ -0,0 +1,18 @@ +package io.oeid.mogakgo.domain.review.domain.enums; + +import lombok.Getter; + +@Getter +public enum ReviewRating { + ONE(-2), + TWO(-1), + THREE(1), + FOUR(2), + FIVE(3); + + private final int value; + + ReviewRating(int value) { + this.value = value; + } +} diff --git a/src/main/java/io/oeid/mogakgo/domain/review/exception/ReviewException.java b/src/main/java/io/oeid/mogakgo/domain/review/exception/ReviewException.java new file mode 100644 index 00000000..9eba9500 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/review/exception/ReviewException.java @@ -0,0 +1,11 @@ +package io.oeid.mogakgo.domain.review.exception; + +import io.oeid.mogakgo.exception.code.ErrorCode; +import io.oeid.mogakgo.exception.exception_class.CustomException; + +public class ReviewException extends CustomException { + + public ReviewException(ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/io/oeid/mogakgo/domain/review/infrastructure/ReviewJpaRepository.java b/src/main/java/io/oeid/mogakgo/domain/review/infrastructure/ReviewJpaRepository.java new file mode 100644 index 00000000..f01b4769 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/review/infrastructure/ReviewJpaRepository.java @@ -0,0 +1,14 @@ +package io.oeid.mogakgo.domain.review.infrastructure; + +import io.oeid.mogakgo.domain.review.domain.Review; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface ReviewJpaRepository extends JpaRepository { + + @Query("select r from Review r where r.sender.id = ?1 and r.receiver.id = ?2 and r.project.id = ?3") + Optional findReviewByProjectData(Long id, Long id1, Long id2); +} \ No newline at end of file diff --git a/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java b/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java index 79503dbe..2ed682d9 100644 --- a/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java +++ b/src/main/java/io/oeid/mogakgo/domain/user/domain/User.java @@ -5,6 +5,7 @@ import io.oeid.mogakgo.domain.achievement.domain.entity.Achievement; import io.oeid.mogakgo.domain.geo.domain.enums.Region; +import io.oeid.mogakgo.domain.review.domain.enums.ReviewRating; import io.oeid.mogakgo.domain.user.domain.enums.Role; import io.oeid.mogakgo.domain.user.exception.UserException; import io.oeid.mogakgo.exception.code.ErrorCode400; @@ -43,6 +44,7 @@ public class User { private static final int MAX_TAG_SIZE = 3; private static final int MAX_AVAILABLE_LIKE_COUNT = 10; + private static final double JANDI_WEIGHT = 2.5; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -111,7 +113,8 @@ public class User { @JoinColumn(name = "achievement_id") private Achievement achievement; - private User(Long githubPk, String githubId, String avatarUrl, String githubUrl, String repositoryUrl) { + private User(Long githubPk, String githubId, String avatarUrl, String githubUrl, + String repositoryUrl) { this.githubPk = githubPk; this.username = githubId; this.githubId = githubId; @@ -119,11 +122,12 @@ private User(Long githubPk, String githubId, String avatarUrl, String githubUrl, this.githubUrl = githubUrl; this.repositoryUrl = repositoryUrl; this.role = Role.ROLE_USER; - this.jandiRate = 0d; + this.jandiRate = 10d; this.signupYn = false; } - public static User of(long githubPk, String username, String avatarUrl, String githubUrl, String repositoryUrl) { + public static User of(long githubPk, String username, String avatarUrl, String githubUrl, + String repositoryUrl) { return new User(githubPk, username, avatarUrl, githubUrl, repositoryUrl); } @@ -145,7 +149,8 @@ public Collection getAuthorities() { return List.of(new SimpleGrantedAuthority(role.name())); } - public void updateGithubInfo(String githubId, String avatarUrl, String githubUrl, String repositoryUrl) { + public void updateGithubInfo(String githubId, String avatarUrl, String githubUrl, + String repositoryUrl) { this.githubId = githubId; this.avatarUrl = avatarUrl; this.githubUrl = githubUrl; @@ -200,7 +205,8 @@ public void updateRegion(Region region) { } } - public void updateUserInfos(String username, String avatarUrl, String bio, Achievement achievement) { + public void updateUserInfos(String username, String avatarUrl, String bio, + Achievement achievement) { updateUsername(username); this.avatarUrl = verifyAvatarUrl(avatarUrl); this.bio = bio; @@ -208,9 +214,12 @@ public void updateUserInfos(String username, String avatarUrl, String bio, Achie deleteAllWantJobTags(); } - //TODO : 추후 구현 필요 - public void decreaseJandiRate() { - return; + public void updateJandiRateByReview(ReviewRating rating, double time) { + this.jandiRate += rating.getValue() * time * JANDI_WEIGHT; + } + + public void updateJandiRateByCancel() { + this.jandiRate += -5 * JANDI_WEIGHT; } private boolean validateAvailableRegionUpdate(Region region) { @@ -225,6 +234,4 @@ private String verifyAvatarUrl(String avatarUrl) { } - - } diff --git a/src/main/java/io/oeid/mogakgo/exception/code/ErrorCode400.java b/src/main/java/io/oeid/mogakgo/exception/code/ErrorCode400.java index 1ab1ae41..84fa77a6 100644 --- a/src/main/java/io/oeid/mogakgo/exception/code/ErrorCode400.java +++ b/src/main/java/io/oeid/mogakgo/exception/code/ErrorCode400.java @@ -56,6 +56,11 @@ public enum ErrorCode400 implements ErrorCode { CHAT_ROOM_CLOSED("E110101", "채팅방이 종료되어 채팅을 할 수 없습니다."), CHAT_ROOM_USER_CANNOT_DUPLICATE("E110102", "채팅방에 중복된 유저가 있습니다."), CHAT_ROOM_USER_NOT_CONTAINS("E110103", "채팅방에 해당 유저가 없습니다."), + + REVIEW_SENDER_OR_RECEIVER_NOT_FOUND("E120101", "리뷰를 작성하기 위한 유저 정보가 존재하지 않습니다."), + REVIEW_USER_DUPLICATED("E120102", "자신에 대한 리뷰는 작성할 수 없습니다."), + REVIEW_PROJECT_NOT_NULL("E120103", "리뷰를 작성하기 위한 프로젝트 정보가 존재하지 않습니다."), + REVIEW_ALREADY_EXISTS("E120104", "이미 작성된 리뷰가 존재합니다."), ; private final HttpStatus httpStatus = HttpStatus.BAD_REQUEST; From 5f1605ab463ca2dbc93fe84fb72793ab0bfc6f20 Mon Sep 17 00:00:00 2001 From: JIN-076 <57834671+JIN-076@users.noreply.github.com> Date: Wed, 28 Feb 2024 14:16:27 +0900 Subject: [PATCH 6/7] Refact/#178 pagination refact (#180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [REFACT] Pagination 정렬 누락 수정 및 최신순 정렬 * [REFACT] 사용자의 프로젝트 매칭 요청 리스트 조회에서 Pagination 정렬 누락 수정 및 최신순 정렬 --- .../ProfileCardLikeRepositoryCustomImpl.java | 4 +++- .../infrastructure/ProfileCardRepositoryCustomImpl.java | 4 +++- .../infrastructure/ProjectRepositoryCustomImpl.java | 4 +++- .../ProjectJoinRequestRepositoryCustomImpl.java | 8 +++++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardLikeRepositoryCustomImpl.java b/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardLikeRepositoryCustomImpl.java index c98d0faf..cb265bb4 100644 --- a/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardLikeRepositoryCustomImpl.java +++ b/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardLikeRepositoryCustomImpl.java @@ -58,6 +58,8 @@ public CursorPaginationResult getLikeInfoBySender( cursorIdCondition(pageable.getCursorId()), senderIdEq(senderId) ) + // 최근순 + .orderBy(profileCardLike.id.desc()) .limit(pageable.getPageSize() + 1) .fetch(); @@ -83,6 +85,6 @@ private BooleanExpression receiveridEq(Long receiverId) { } private BooleanExpression cursorIdCondition(Long cursorId) { - return cursorId != null ? profileCardLike.id.gt(cursorId) : null; + return cursorId != null ? profileCardLike.id.lt(cursorId) : null; } } diff --git a/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardRepositoryCustomImpl.java b/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardRepositoryCustomImpl.java index a8d898d6..7684dd55 100644 --- a/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardRepositoryCustomImpl.java +++ b/src/main/java/io/oeid/mogakgo/domain/profile/infrastructure/ProfileCardRepositoryCustomImpl.java @@ -35,6 +35,8 @@ public CursorPaginationResult findByConditionWithPaginati regionEq(region), deletedProfileCardEq() ) + // 최근순 + .orderBy(profileCard.id.desc()) .limit(pageable.getPageSize() + 1) .fetch(); @@ -69,7 +71,7 @@ private BooleanExpression userIdEq(Long userId) { } private BooleanExpression cursorIdCondition(Long cursorId) { - return cursorId != null ? profileCard.id.gt(cursorId) : null; + return cursorId != null ? profileCard.id.lt(cursorId) : null; } private BooleanExpression deletedProfileCardEq() { diff --git a/src/main/java/io/oeid/mogakgo/domain/project/infrastructure/ProjectRepositoryCustomImpl.java b/src/main/java/io/oeid/mogakgo/domain/project/infrastructure/ProjectRepositoryCustomImpl.java index 20c73887..c407159b 100644 --- a/src/main/java/io/oeid/mogakgo/domain/project/infrastructure/ProjectRepositoryCustomImpl.java +++ b/src/main/java/io/oeid/mogakgo/domain/project/infrastructure/ProjectRepositoryCustomImpl.java @@ -43,6 +43,8 @@ public CursorPaginationResult findByConditionWithPagination projectStatusEq(projectStatus), createdAtEq(today) ) + // 최근순 + .orderBy(project.id.desc()) .limit(pageable.getPageSize() + 1) .fetch(); @@ -90,7 +92,7 @@ public List getDensityRankProjectsByRegion(int limit) { } private BooleanExpression cursorIdCondition(Long cursorId) { - return cursorId != null ? project.id.gt(cursorId) : null; + return cursorId != null ? project.id.lt(cursorId) : null; } private BooleanExpression userIdEq(Long userId) { diff --git a/src/main/java/io/oeid/mogakgo/domain/project_join_req/infrastructure/ProjectJoinRequestRepositoryCustomImpl.java b/src/main/java/io/oeid/mogakgo/domain/project_join_req/infrastructure/ProjectJoinRequestRepositoryCustomImpl.java index a2e05315..3114f1ef 100644 --- a/src/main/java/io/oeid/mogakgo/domain/project_join_req/infrastructure/ProjectJoinRequestRepositoryCustomImpl.java +++ b/src/main/java/io/oeid/mogakgo/domain/project_join_req/infrastructure/ProjectJoinRequestRepositoryCustomImpl.java @@ -84,11 +84,13 @@ public CursorPaginationResult getBySenderIdWithP ) { List entities = jpaQueryFactory.selectFrom(projectJoinRequest) .where( - cursorIdCondition(pageable.getCursorId()), + cursorIdConditionForDesc(pageable.getCursorId()), senderIdEq(senderId), projectIdEq(projectId), requestStatusEq(requestStatus) ) + // 최근순 + .orderBy(projectJoinRequest.id.desc()) .limit(pageable.getPageSize() + 1) .fetch(); @@ -125,4 +127,8 @@ private BooleanExpression cursorIdCondition(Long cursorId) { return cursorId != null ? projectJoinRequest.id.gt(cursorId) : null; } + private BooleanExpression cursorIdConditionForDesc(Long cursorId) { + return cursorId != null ? projectJoinRequest.id.lt(cursorId) : null; + } + } From f1669fec9cf6ce75baed1224c25355802277bbdb Mon Sep 17 00:00:00 2001 From: KyungMin Lee Date: Wed, 28 Feb 2024 14:16:33 +0900 Subject: [PATCH 7/7] Feat/#142 jandi rate (#181) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FEAT] 유저 잔디력 조회 서비스 기능 추가 * [FEAT] 유저 잔디력 조회 API 및 Swagger 추가 --- .../common/swagger/template/UserSwagger.java | 15 +++++++++++++ .../domain/user/application/UserService.java | 6 ++++++ .../application/dto/res/UserJandiRateRes.java | 21 +++++++++++++++++++ .../user/presentation/UserController.java | 8 +++++++ 4 files changed, 50 insertions(+) create mode 100644 src/main/java/io/oeid/mogakgo/domain/user/application/dto/res/UserJandiRateRes.java diff --git a/src/main/java/io/oeid/mogakgo/common/swagger/template/UserSwagger.java b/src/main/java/io/oeid/mogakgo/common/swagger/template/UserSwagger.java index 82fef30f..a2836b2f 100644 --- a/src/main/java/io/oeid/mogakgo/common/swagger/template/UserSwagger.java +++ b/src/main/java/io/oeid/mogakgo/common/swagger/template/UserSwagger.java @@ -3,6 +3,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples; +import io.oeid.mogakgo.domain.user.application.dto.res.UserJandiRateRes; import io.oeid.mogakgo.domain.user.presentation.dto.req.UserSignUpApiReq; import io.oeid.mogakgo.domain.user.presentation.dto.req.UserUpdateApiReq; import io.oeid.mogakgo.domain.user.presentation.dto.res.UserDevelopLanguageApiRes; @@ -13,6 +14,7 @@ import io.oeid.mogakgo.exception.dto.ErrorResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; @@ -109,5 +111,18 @@ ResponseEntity> userDevelopLanguageApi( }) ResponseEntity userUpdateApi(@Parameter(hidden = true) Long userId, UserUpdateApiReq request); + + + @Operation(summary = "회원 잔디 점수 조회", description = "회원의 잔디 점수를 조회할 때 사용하는 API") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "회원 잔디 점수 조회 성공", + content = @Content(schema = @Schema(implementation = UserJandiRateRes.class))), + @ApiResponse(responseCode = "404", description = "해당 유저가 존재하지 않음", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorResponse.class), + examples = @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND))), + }) + ResponseEntity userJandiRateApi(@Parameter(in = ParameterIn.PATH) Long userId); } diff --git a/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java b/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java index 39e12c42..fc4d493a 100644 --- a/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java +++ b/src/main/java/io/oeid/mogakgo/domain/user/application/UserService.java @@ -7,6 +7,7 @@ import io.oeid.mogakgo.domain.user.application.dto.req.UserSignUpRequest; import io.oeid.mogakgo.domain.user.application.dto.req.UserUpdateReq; import io.oeid.mogakgo.domain.user.application.dto.res.UserDevelopLanguageRes; +import io.oeid.mogakgo.domain.user.application.dto.res.UserJandiRateRes; import io.oeid.mogakgo.domain.user.application.dto.res.UserProfileResponse; import io.oeid.mogakgo.domain.user.application.dto.res.UserSignUpResponse; import io.oeid.mogakgo.domain.user.application.dto.res.UserUpdateRes; @@ -106,6 +107,11 @@ public void deleteUser(Long userId) { user.delete(); } + public UserJandiRateRes getUserJandiRate(Long userId) { + User user = userCommonService.getUserById(userId); + return UserJandiRateRes.of(user.getId(), user.getJandiRate()); + } + private void validateWantedJobDuplicate(List wantedJobs) { Set wantedJobSet = new HashSet<>(wantedJobs); if (wantedJobSet.size() != wantedJobs.size()) { diff --git a/src/main/java/io/oeid/mogakgo/domain/user/application/dto/res/UserJandiRateRes.java b/src/main/java/io/oeid/mogakgo/domain/user/application/dto/res/UserJandiRateRes.java new file mode 100644 index 00000000..49615284 --- /dev/null +++ b/src/main/java/io/oeid/mogakgo/domain/user/application/dto/res/UserJandiRateRes.java @@ -0,0 +1,21 @@ +package io.oeid.mogakgo.domain.user.application.dto.res; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Schema(description = "유저의 잔디 점수") +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class UserJandiRateRes { + + @Schema(description = "유저 아이디") + private Long userId; + @Schema(description = "유저의 잔디 점수") + private Double jandiRate; + + public static UserJandiRateRes of(Long userId, Double jandiRate) { + return new UserJandiRateRes(userId, jandiRate); + } +} diff --git a/src/main/java/io/oeid/mogakgo/domain/user/presentation/UserController.java b/src/main/java/io/oeid/mogakgo/domain/user/presentation/UserController.java index 250f33c2..0f03059e 100644 --- a/src/main/java/io/oeid/mogakgo/domain/user/presentation/UserController.java +++ b/src/main/java/io/oeid/mogakgo/domain/user/presentation/UserController.java @@ -5,6 +5,7 @@ import io.oeid.mogakgo.domain.matching.application.UserMatchingService; import io.oeid.mogakgo.domain.user.application.UserService; import io.oeid.mogakgo.domain.user.application.dto.req.UserUpdateReq; +import io.oeid.mogakgo.domain.user.application.dto.res.UserJandiRateRes; import io.oeid.mogakgo.domain.user.presentation.dto.req.UserSignUpApiReq; import io.oeid.mogakgo.domain.user.presentation.dto.req.UserUpdateApiReq; import io.oeid.mogakgo.domain.user.presentation.dto.res.UserDevelopLanguageApiRes; @@ -19,6 +20,7 @@ import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -44,6 +46,12 @@ public ResponseEntity> userDevelopLanguageApi( return ResponseEntity.ok(response.stream().map(UserDevelopLanguageApiRes::from).toList()); } + @GetMapping("/jandi-rating/{userId}") + public ResponseEntity userJandiRateApi(@PathVariable Long userId) { + var result = userService.getUserJandiRate(userId); + return ResponseEntity.ok(result); + } + @PatchMapping public ResponseEntity userUpdateApi(@UserId Long userId, @RequestBody @Valid UserUpdateApiReq request) {