From ab51cccbbd8e42bdbb143ee0139abe62b60e1a89 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:20:09 +0900 Subject: [PATCH 01/29] =?UTF-8?q?#18=20[feat]=20pen=20->=20writer=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EC=9D=98=20=EB=AA=A8=EC=9E=84=20=EA=B4=80=EB=A0=A8=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/WriterName.java} | 6 ++++-- .../repository/WriterNameRepository.java | 11 +++++++++++ .../writerName/serivce/WriterNameService.java | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) rename module-domain/src/main/java/com/mile/{penNameProfile/domain/PenName.java => writerName/domain/WriterName.java} (84%) create mode 100644 module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java create mode 100644 module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java diff --git a/module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java b/module-domain/src/main/java/com/mile/writerName/domain/WriterName.java similarity index 84% rename from module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java rename to module-domain/src/main/java/com/mile/writerName/domain/WriterName.java index 435f1592..fa112626 100644 --- a/module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java +++ b/module-domain/src/main/java/com/mile/writerName/domain/WriterName.java @@ -1,4 +1,4 @@ -package com.mile.penNameProfile.domain; +package com.mile.writerName.domain; import com.mile.moim.domain.Moim; import com.mile.user.domain.User; @@ -7,9 +7,11 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import lombok.Getter; @Entity -public class PenName { +@Getter +public class WriterName { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java b/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java new file mode 100644 index 00000000..4b3871ad --- /dev/null +++ b/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java @@ -0,0 +1,11 @@ +package com.mile.writerName.repository; + +import com.mile.writerName.domain.WriterName; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface WriterNameRepository extends JpaRepository { + + Optional findByMoimIdAndWriterId(final Long moimId, final Long userId); +} diff --git a/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java new file mode 100644 index 00000000..937a10d6 --- /dev/null +++ b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java @@ -0,0 +1,19 @@ +package com.mile.writerName.serivce; + +import com.mile.writerName.repository.WriterNameRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class WriterNameService { + private final WriterNameRepository penNameRepository; + + public boolean isUserInMoim( + final Long moimId, + final Long writerId + ) { + return penNameRepository.findByMoimIdAndWriterId(moimId, writerId).isPresent(); + } + +} From 756043426023b47bcbacbf409a8d86fed9271b25 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:20:51 +0900 Subject: [PATCH 02/29] =?UTF-8?q?#18=20[feat]=20=EA=B8=80=EA=B0=90=20list?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=20API=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mile/controller/moim/MoimController.java | 29 ++++++++++++++++ .../moim/MoimControllerSwagger.java | 33 +++++++++++++++++++ .../moim/serivce/dto/ContentListResponse.java | 15 +++++++++ .../topic/serivce/dto/ContentResponse.java | 14 ++++++++ 4 files changed, 91 insertions(+) create mode 100644 module-api/src/main/java/com/mile/controller/moim/MoimController.java create mode 100644 module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java create mode 100644 module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java create mode 100644 module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java new file mode 100644 index 00000000..198f8acf --- /dev/null +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -0,0 +1,29 @@ +package com.mile.controller.moim; + +import com.mile.dto.SuccessResponse; +import com.mile.exception.message.SuccessMessage; +import com.mile.moim.serivce.MoimService; +import com.mile.moim.serivce.dto.ContentListResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/moim") +public class MoimController { + + private final MoimService moimService; + + @GetMapping("/{moimId}") + public SuccessResponse getTopicsFromMoim( + @PathVariable final Long moimId, + final Principal principal + ) { + return SuccessResponse.of(SuccessMessage.TOPIC_SEARCH_SUCCESS, moimService.getContentsFromMoim(moimId, Long.valueOf(principal.getName()))); + } +} diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java new file mode 100644 index 00000000..d1b6110a --- /dev/null +++ b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java @@ -0,0 +1,33 @@ +package com.mile.controller.moim; + +import com.mile.dto.ErrorResponse; +import com.mile.dto.SuccessResponse; +import com.mile.moim.serivce.dto.ContentListResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PathVariable; + +import java.security.Principal; + +@Tag(name = "Moim", description = "모임 관련 API") +public interface MoimControllerSwagger { + @Operation(summary = "에디터 상단 글감 조회") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "글감 조회가 완료되었습니다.", + content = @Content(schema = @Schema(implementation = SuccessResponse.class))), + @ApiResponse(responseCode = "403", description = "해당 사용자는 모임에 접근 권한이 없습니다."), + @ApiResponse(responseCode = "404", description = "해당 모임의 주제가 존재하지 않습니다."), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + SuccessResponse getTopicsFromMoim( + @PathVariable final Long moimId, + final Principal principal + ); +} diff --git a/module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java b/module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java new file mode 100644 index 00000000..0738d0cb --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java @@ -0,0 +1,15 @@ +package com.mile.moim.serivce.dto; + +import com.mile.topic.serivce.dto.ContentResponse; + +import java.util.List; + +public record ContentListResponse( + List topics +) { + public static ContentListResponse of( + final List topics + ) { + return new ContentListResponse(topics); + } +} diff --git a/module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java b/module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java new file mode 100644 index 00000000..69cf182a --- /dev/null +++ b/module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java @@ -0,0 +1,14 @@ +package com.mile.topic.serivce.dto; + +import com.mile.topic.domain.Topic; + +public record ContentResponse( + Long topicId, + String topicName +) { + public static ContentResponse of( + final Topic topic + ) { + return new ContentResponse(topic.getId(), topic.getTopic()); + } +} From ae8d584bd4b85ec9f892c71921ca6dd945861e7c Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:21:08 +0900 Subject: [PATCH 03/29] =?UTF-8?q?#18=20[test]=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B4=80=EB=A0=A8=20=EB=AA=A8=EB=93=88=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ module-api/build.gradle | 7 +++++++ module-api/src/test/java/com/mile/ApiApplicationTests.java | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 module-api/src/test/java/com/mile/ApiApplicationTests.java diff --git a/build.gradle b/build.gradle index 04dfb8ed..ceeb29f5 100644 --- a/build.gradle +++ b/build.gradle @@ -25,6 +25,9 @@ dependencies { //Swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' + //Test + testImplementation 'org.springframework.boot:spring-boot-starter-test' + } subprojects { diff --git a/module-api/build.gradle b/module-api/build.gradle index 6bce34f1..428c16b3 100644 --- a/module-api/build.gradle +++ b/module-api/build.gradle @@ -28,6 +28,10 @@ dependencies { //Aop implementation 'org.springframework.boot:spring-boot-starter-aop' + + //Test + testImplementation 'org.springframework.boot:spring-boot-starter-test' + } ext { @@ -39,4 +43,7 @@ dependencyManagement { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } +} +tasks.named('test') { + useJUnitPlatform() } \ No newline at end of file diff --git a/module-api/src/test/java/com/mile/ApiApplicationTests.java b/module-api/src/test/java/com/mile/ApiApplicationTests.java new file mode 100644 index 00000000..e1b0b713 --- /dev/null +++ b/module-api/src/test/java/com/mile/ApiApplicationTests.java @@ -0,0 +1,7 @@ +package com.mile; + +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApiApplicationTests { +} \ No newline at end of file From a0be6c589682007b9809a7b538c1c441abff40d1 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:21:36 +0900 Subject: [PATCH 04/29] =?UTF-8?q?#18=20[feat]=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mile/exception/message/ErrorMessage.java | 8 ++++++++ .../com/mile/exception/message/SuccessMessage.java | 4 +++- .../com/mile/exception/model/ForbiddenException.java | 9 +++++++++ .../com/mile/handler/GlobalExceptionHandler.java | 12 ++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 module-common/src/main/java/com/mile/exception/model/ForbiddenException.java diff --git a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java index 1c1ccc11..b2657c60 100644 --- a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java @@ -13,12 +13,16 @@ public enum ErrorMessage { */ USER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 유저는 존재하지 않습니다."), REFRESH_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 유저의 리프레시 토큰이 존재하지 않습니다."), + MOIM_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 글모임이 존재하지 않습니다."), + CONTENT_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 모임의 주제가 존재하지 않습니다."), + HANDLER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "요청하신 URL은 정보가 없습니다."), /* Bad Request */ ENUM_VALUE_BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "요청한 값이 유효하지 않습니다."), AUTHENTICATION_CODE_EXPIRED(HttpStatus.BAD_REQUEST.value(), "인가 코드가 만료되었습니다."), SOCIAL_TYPE_BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "로그인 요청이 유효하지 않습니다."), + BEARER_LOST_ERROR(HttpStatus.BAD_REQUEST.value(), "토큰의 요청에 Bearer이 담겨 있지 않습니다."), /* Unauthorized */ @@ -26,6 +30,10 @@ public enum ErrorMessage { TOKEN_INCORRECT_ERROR(HttpStatus.UNAUTHORIZED.value(), "리프레시 토큰이 유효하지 않습니다."), TOKEN_VALIDATION_ERROR(HttpStatus.UNAUTHORIZED.value(), "사용자 검증 토큰이 유효하지 안습니다."), /* + Forbidden + */ + USER_AUTHENTICATE_ERROR(HttpStatus.FORBIDDEN.value(), "해당 사용자는 모임에 접근 권한이 없습니다."), + /* Internal Server Error */ INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "서버 내부 오류입니다."); diff --git a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java index d4ae4aca..4ec7d2f5 100644 --- a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java @@ -10,7 +10,9 @@ public enum SuccessMessage { LOGIN_SUCCESS(HttpStatus.OK.value(), "소셜 로그인이 완료되었습니다."), ISSUE_ACCESS_TOKEN_SUCCESS(HttpStatus.OK.value(), "액세스 토큰 재발급이 완료되었습니다."), USER_DELETE_SUCCESS(HttpStatus.OK.value(), "회원 삭제가 완료되었습니다."), - LOGOUT_SUCCESS(HttpStatus.OK.value(), "로그아웃이 완료되었습니다.") + LOGOUT_SUCCESS(HttpStatus.OK.value(), "로그아웃이 완료되었습니다."), + + TOPIC_SEARCH_SUCCESS(HttpStatus.OK.value(), "주제 조회가 완료되었습니다."), ; int status; diff --git a/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java b/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java new file mode 100644 index 00000000..629c8f74 --- /dev/null +++ b/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java @@ -0,0 +1,9 @@ +package com.mile.exception.model; + +import com.mile.exception.message.ErrorMessage; + +public class ForbiddenException extends MileException { + public ForbiddenException(final ErrorMessage errorMessage) { + super(errorMessage); + } +} diff --git a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java index 154adebd..cc3046f3 100644 --- a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import com.mile.dto.ErrorResponse; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; +import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.JwtValidationException; import com.mile.exception.model.NotFoundException; import com.mile.exception.model.UnauthorizedException; @@ -13,6 +14,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.NoHandlerFoundException; @Slf4j @RestControllerAdvice @@ -38,11 +40,21 @@ public ResponseEntity handleJwtValidationException(final JwtValid return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ErrorResponse.of(e.getErrorMessage())); } + @ExceptionHandler(ForbiddenException.class) + public ResponseEntity handleForbiddenException(final UnauthorizedException e) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ErrorResponse.of(e.getErrorMessage())); + } + @ExceptionHandler(NotFoundException.class) public ResponseEntity handleNotFoundException(final NotFoundException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of(e.getErrorMessage())); } + @ExceptionHandler({NoHandlerFoundException.class}) + public ResponseEntity handleNoHandlerFoundException(final NoHandlerFoundException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of(ErrorMessage.HANDLER_NOT_FOUND)); + } + @ExceptionHandler(Exception.class) protected ResponseEntity handleException(final Exception error, final HttpServletRequest request) { log.error("================================================NEW==============================================="); From e0238680649368e55292d3b733aba4b724548cd2 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:21:50 +0900 Subject: [PATCH 05/29] #18 [feat] pen -> writer --- .../mile/penNameProfile/serivce/PenNameProfileService.java | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java diff --git a/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java b/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java deleted file mode 100644 index 1622f9d5..00000000 --- a/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mile.penNameProfile.serivce; - -import org.springframework.stereotype.Service; - -@Service -public class PenNameProfileService { -} From d108ca0d586da76d9b2cfcd46486abb8c15b8a90 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:23:04 +0900 Subject: [PATCH 06/29] =?UTF-8?q?#18=20[feat]=20Security=20Config=20WHITE?= =?UTF-8?q?=20LIST=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/mile/config/security/SecurityConfig.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java index b7896897..ff9e7945 100644 --- a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java +++ b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java @@ -24,8 +24,9 @@ public class SecurityConfig { private static final String[] AUTH_WHITELIST = { - "/user/login", - "/user/token-refresh", + "/api/user/login", + "/api/user/token-refresh", + "/api/**", "/actuator/health", "/v3/api-docs/**", "/swagger-ui/**", From 12e6d646d96a059d54d0efead9c6db2335fe2cd3 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:23:57 +0900 Subject: [PATCH 07/29] =?UTF-8?q?#18=20[feat]=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20getter=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?topic=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=B3=80=EA=B2=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/mile/config/BaseTimeEntity.java | 3 +++ module-domain/src/main/java/com/mile/post/Post.java | 3 ++- .../src/main/java/com/mile/topic/domain/Topic.java | 9 ++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java b/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java index 9d958a42..1d4cc793 100644 --- a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java +++ b/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java @@ -3,9 +3,12 @@ import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; import java.time.LocalDateTime; + +import lombok.Getter; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; +@Getter @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public abstract class BaseTimeEntity { diff --git a/module-domain/src/main/java/com/mile/post/Post.java b/module-domain/src/main/java/com/mile/post/Post.java index d5cd3ffd..2f946d33 100644 --- a/module-domain/src/main/java/com/mile/post/Post.java +++ b/module-domain/src/main/java/com/mile/post/Post.java @@ -1,5 +1,6 @@ package com.mile.post; +import com.mile.config.BaseTimeEntity; import com.mile.topic.domain.Topic; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -8,7 +9,7 @@ import jakarta.persistence.ManyToOne; @Entity -public class Post { +public class Post extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/module-domain/src/main/java/com/mile/topic/domain/Topic.java b/module-domain/src/main/java/com/mile/topic/domain/Topic.java index 5a0757af..027b1a9f 100644 --- a/module-domain/src/main/java/com/mile/topic/domain/Topic.java +++ b/module-domain/src/main/java/com/mile/topic/domain/Topic.java @@ -1,14 +1,17 @@ package com.mile.topic.domain; +import com.mile.config.BaseTimeEntity; import com.mile.moim.domain.Moim; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import lombok.Getter; @Entity -public class Topic { +@Getter +public class Topic extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -16,7 +19,7 @@ public class Topic { @ManyToOne private Moim moim; + private String keyword; private String topic; - private int week; - private boolean isClosed; + private String description; } From cca005c43f80b0ba2f2b369e8d1dc308fa82a22b Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:24:15 +0900 Subject: [PATCH 08/29] =?UTF-8?q?#18=20[feat]=20=EA=B8=80=EA=B0=90=20List?= =?UTF-8?q?=20=EB=B0=98=ED=99=98=20API=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mile/moim/repository/MoimRepository.java | 7 +++ .../com/mile/moim/serivce/MoimService.java | 26 ++++++++++ .../topic/repository/TopicRepository.java | 11 +++++ .../com/mile/topic/serivce/TopicService.java | 47 +++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java create mode 100644 module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java diff --git a/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java b/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java new file mode 100644 index 00000000..b52ac9c8 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java @@ -0,0 +1,7 @@ +package com.mile.moim.repository; + +import com.mile.moim.domain.Moim; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MoimRepository extends JpaRepository { +} diff --git a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java index aa140403..da62f36b 100644 --- a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java @@ -1,7 +1,33 @@ package com.mile.moim.serivce; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.UnauthorizedException; +import com.mile.moim.serivce.dto.ContentListResponse; +import com.mile.topic.serivce.TopicService; +import com.mile.writerName.serivce.WriterNameService; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class MoimService { + private final WriterNameService penNameService; + private final TopicService topicService; + + public ContentListResponse getContentsFromMoim( + final Long moimId, + final Long userId + ) { + authenticateUserOfMoim(moimId, userId); + return ContentListResponse.of(topicService.getContentsFromMoim(moimId)); + } + + private void authenticateUserOfMoim( + final Long moimId, + final Long userId + ) { + if (!penNameService.isUserInMoim(moimId, userId)) { + throw new UnauthorizedException(ErrorMessage.USER_AUTHENTICATE_ERROR); + } + } } diff --git a/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java new file mode 100644 index 00000000..72e678df --- /dev/null +++ b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java @@ -0,0 +1,11 @@ +package com.mile.topic.repository; + +import com.mile.topic.domain.Topic; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface TopicRepository extends JpaRepository { + + public List findByMoimId(final Long moimId); +} diff --git a/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java b/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java index 70b6e999..7556e30e 100644 --- a/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java +++ b/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java @@ -1,7 +1,54 @@ package com.mile.topic.serivce; +import com.mile.config.BaseTimeEntity; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.NotFoundException; +import com.mile.topic.domain.Topic; +import com.mile.topic.repository.TopicRepository; +import com.mile.topic.serivce.dto.ContentResponse; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + @Service +@RequiredArgsConstructor public class TopicService { + + private final TopicRepository topicRepository; + + public List getContentsFromMoim( + final Long moimId + ) { + List topicList = sortByCreatedAt(findByMoimId(moimId)); + isContentsEmpty(topicList); + return topicList + .stream() + .map(ContentResponse::of) + .collect(Collectors.toList()); + } + + private void isContentsEmpty( + final List topicList + ) { + if (topicList.isEmpty()) { + throw new NotFoundException(ErrorMessage.CONTENT_NOT_FOUND); + } + } + + private List findByMoimId( + final Long moimId + ) { + return topicRepository.findByMoimId(moimId); + } + + private List sortByCreatedAt( + final List topicList + ) { + return topicList.stream() + .sorted(Comparator.comparing(BaseTimeEntity::getCreatedAt)) + .collect(Collectors.toList()); + } } From 709058e660ab564ba37a259b60999857671dd0c3 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:24:28 +0900 Subject: [PATCH 09/29] =?UTF-8?q?#18=20[feat]=20bearer=20+=20=EC=9D=B4=20?= =?UTF-8?q?=EC=95=84=EB=8B=90=20=EB=95=8C=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/mile/filter/JwtAuthenticationFilter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java index 3a14f1a4..2bcf9b1f 100644 --- a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java +++ b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java @@ -2,6 +2,7 @@ import com.mile.authentication.UserAuthentication; import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.BadRequestException; import com.mile.exception.model.JwtValidationException; import com.mile.jwt.JwtTokenProvider; import com.mile.jwt.JwtValidationType; @@ -49,7 +50,8 @@ private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring("Bearer ".length()); + } else { + throw new BadRequestException(ErrorMessage.BEARER_LOST_ERROR); } - return null; } } \ No newline at end of file From 89483b7115b0c9bd2a30d2fcb12e998eb7a3a272 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:26:41 +0900 Subject: [PATCH 10/29] =?UTF-8?q?#18=20[feat]=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/mile/handler/GlobalExceptionHandler.java | 2 +- .../src/main/java/com/mile/moim/serivce/MoimService.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java index cc3046f3..3d5d564c 100644 --- a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java @@ -41,7 +41,7 @@ public ResponseEntity handleJwtValidationException(final JwtValid } @ExceptionHandler(ForbiddenException.class) - public ResponseEntity handleForbiddenException(final UnauthorizedException e) { + public ResponseEntity handleForbiddenException(final ForbiddenException e) { return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ErrorResponse.of(e.getErrorMessage())); } diff --git a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java index da62f36b..c5bc84f8 100644 --- a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java @@ -1,6 +1,7 @@ package com.mile.moim.serivce; import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.UnauthorizedException; import com.mile.moim.serivce.dto.ContentListResponse; import com.mile.topic.serivce.TopicService; @@ -27,7 +28,7 @@ private void authenticateUserOfMoim( final Long userId ) { if (!penNameService.isUserInMoim(moimId, userId)) { - throw new UnauthorizedException(ErrorMessage.USER_AUTHENTICATE_ERROR); + throw new ForbiddenException(ErrorMessage.USER_AUTHENTICATE_ERROR); } } } From c18feb26da9456408182ac5c30fc2a366161fc71 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:37:25 +0900 Subject: [PATCH 11/29] #18 [feat] moim controller swagger --- .../src/main/java/com/mile/controller/moim/MoimController.java | 3 ++- .../src/main/java/com/mile/config/security/SecurityConfig.java | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java index 198f8acf..7a791bb1 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimController.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -15,11 +15,12 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/moim") -public class MoimController { +public class MoimController implements MoimControllerSwagger { private final MoimService moimService; @GetMapping("/{moimId}") + @Override public SuccessResponse getTopicsFromMoim( @PathVariable final Long moimId, final Principal principal diff --git a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java index ff9e7945..0b6f4e1a 100644 --- a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java +++ b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java @@ -24,8 +24,6 @@ public class SecurityConfig { private static final String[] AUTH_WHITELIST = { - "/api/user/login", - "/api/user/token-refresh", "/api/**", "/actuator/health", "/v3/api-docs/**", From ead69ad691a02a52dd3f551569bdd2d95bfa27e2 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:20:09 +0900 Subject: [PATCH 12/29] =?UTF-8?q?#18=20[feat]=20pen=20->=20writer=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/WriterName.java} | 6 ++++-- .../repository/WriterNameRepository.java | 11 +++++++++++ .../writerName/serivce/WriterNameService.java | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) rename module-domain/src/main/java/com/mile/{penNameProfile/domain/PenName.java => writerName/domain/WriterName.java} (84%) create mode 100644 module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java create mode 100644 module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java diff --git a/module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java b/module-domain/src/main/java/com/mile/writerName/domain/WriterName.java similarity index 84% rename from module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java rename to module-domain/src/main/java/com/mile/writerName/domain/WriterName.java index 435f1592..fa112626 100644 --- a/module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java +++ b/module-domain/src/main/java/com/mile/writerName/domain/WriterName.java @@ -1,4 +1,4 @@ -package com.mile.penNameProfile.domain; +package com.mile.writerName.domain; import com.mile.moim.domain.Moim; import com.mile.user.domain.User; @@ -7,9 +7,11 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import lombok.Getter; @Entity -public class PenName { +@Getter +public class WriterName { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java b/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java new file mode 100644 index 00000000..4b3871ad --- /dev/null +++ b/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java @@ -0,0 +1,11 @@ +package com.mile.writerName.repository; + +import com.mile.writerName.domain.WriterName; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface WriterNameRepository extends JpaRepository { + + Optional findByMoimIdAndWriterId(final Long moimId, final Long userId); +} diff --git a/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java new file mode 100644 index 00000000..937a10d6 --- /dev/null +++ b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java @@ -0,0 +1,19 @@ +package com.mile.writerName.serivce; + +import com.mile.writerName.repository.WriterNameRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class WriterNameService { + private final WriterNameRepository penNameRepository; + + public boolean isUserInMoim( + final Long moimId, + final Long writerId + ) { + return penNameRepository.findByMoimIdAndWriterId(moimId, writerId).isPresent(); + } + +} From 416baaa5ca19bdc692118c67c67390552ecb3d16 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:20:51 +0900 Subject: [PATCH 13/29] =?UTF-8?q?#18=20[feat]=20=EA=B8=80=EA=B0=90=20list?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=20API=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mile/controller/moim/MoimController.java | 29 ++++++++++++++++ .../moim/MoimControllerSwagger.java | 33 +++++++++++++++++++ .../moim/serivce/dto/ContentListResponse.java | 15 +++++++++ .../topic/serivce/dto/ContentResponse.java | 14 ++++++++ 4 files changed, 91 insertions(+) create mode 100644 module-api/src/main/java/com/mile/controller/moim/MoimController.java create mode 100644 module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java create mode 100644 module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java create mode 100644 module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java new file mode 100644 index 00000000..198f8acf --- /dev/null +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -0,0 +1,29 @@ +package com.mile.controller.moim; + +import com.mile.dto.SuccessResponse; +import com.mile.exception.message.SuccessMessage; +import com.mile.moim.serivce.MoimService; +import com.mile.moim.serivce.dto.ContentListResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/moim") +public class MoimController { + + private final MoimService moimService; + + @GetMapping("/{moimId}") + public SuccessResponse getTopicsFromMoim( + @PathVariable final Long moimId, + final Principal principal + ) { + return SuccessResponse.of(SuccessMessage.TOPIC_SEARCH_SUCCESS, moimService.getContentsFromMoim(moimId, Long.valueOf(principal.getName()))); + } +} diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java new file mode 100644 index 00000000..d1b6110a --- /dev/null +++ b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java @@ -0,0 +1,33 @@ +package com.mile.controller.moim; + +import com.mile.dto.ErrorResponse; +import com.mile.dto.SuccessResponse; +import com.mile.moim.serivce.dto.ContentListResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PathVariable; + +import java.security.Principal; + +@Tag(name = "Moim", description = "모임 관련 API") +public interface MoimControllerSwagger { + @Operation(summary = "에디터 상단 글감 조회") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "글감 조회가 완료되었습니다.", + content = @Content(schema = @Schema(implementation = SuccessResponse.class))), + @ApiResponse(responseCode = "403", description = "해당 사용자는 모임에 접근 권한이 없습니다."), + @ApiResponse(responseCode = "404", description = "해당 모임의 주제가 존재하지 않습니다."), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + SuccessResponse getTopicsFromMoim( + @PathVariable final Long moimId, + final Principal principal + ); +} diff --git a/module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java b/module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java new file mode 100644 index 00000000..0738d0cb --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/serivce/dto/ContentListResponse.java @@ -0,0 +1,15 @@ +package com.mile.moim.serivce.dto; + +import com.mile.topic.serivce.dto.ContentResponse; + +import java.util.List; + +public record ContentListResponse( + List topics +) { + public static ContentListResponse of( + final List topics + ) { + return new ContentListResponse(topics); + } +} diff --git a/module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java b/module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java new file mode 100644 index 00000000..69cf182a --- /dev/null +++ b/module-domain/src/main/java/com/mile/topic/serivce/dto/ContentResponse.java @@ -0,0 +1,14 @@ +package com.mile.topic.serivce.dto; + +import com.mile.topic.domain.Topic; + +public record ContentResponse( + Long topicId, + String topicName +) { + public static ContentResponse of( + final Topic topic + ) { + return new ContentResponse(topic.getId(), topic.getTopic()); + } +} From f3c54d5866b3fa6f1b77c4be004f4ae62b416f8e Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:21:08 +0900 Subject: [PATCH 14/29] =?UTF-8?q?#18=20[test]=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B4=80=EB=A0=A8=20=EB=AA=A8=EB=93=88=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ module-api/build.gradle | 7 +++++++ module-api/src/test/java/com/mile/ApiApplicationTests.java | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 module-api/src/test/java/com/mile/ApiApplicationTests.java diff --git a/build.gradle b/build.gradle index 04dfb8ed..ceeb29f5 100644 --- a/build.gradle +++ b/build.gradle @@ -25,6 +25,9 @@ dependencies { //Swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' + //Test + testImplementation 'org.springframework.boot:spring-boot-starter-test' + } subprojects { diff --git a/module-api/build.gradle b/module-api/build.gradle index 6bce34f1..428c16b3 100644 --- a/module-api/build.gradle +++ b/module-api/build.gradle @@ -28,6 +28,10 @@ dependencies { //Aop implementation 'org.springframework.boot:spring-boot-starter-aop' + + //Test + testImplementation 'org.springframework.boot:spring-boot-starter-test' + } ext { @@ -39,4 +43,7 @@ dependencyManagement { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } +} +tasks.named('test') { + useJUnitPlatform() } \ No newline at end of file diff --git a/module-api/src/test/java/com/mile/ApiApplicationTests.java b/module-api/src/test/java/com/mile/ApiApplicationTests.java new file mode 100644 index 00000000..e1b0b713 --- /dev/null +++ b/module-api/src/test/java/com/mile/ApiApplicationTests.java @@ -0,0 +1,7 @@ +package com.mile; + +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApiApplicationTests { +} \ No newline at end of file From 71ea9c279b3eb4fd6ce3fb0ae7e289043316a52f Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:21:36 +0900 Subject: [PATCH 15/29] =?UTF-8?q?#18=20[feat]=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mile/exception/message/ErrorMessage.java | 8 ++++++++ .../com/mile/exception/message/SuccessMessage.java | 4 +++- .../com/mile/exception/model/ForbiddenException.java | 9 +++++++++ .../com/mile/handler/GlobalExceptionHandler.java | 12 ++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 module-common/src/main/java/com/mile/exception/model/ForbiddenException.java diff --git a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java index 1c1ccc11..b2657c60 100644 --- a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java @@ -13,12 +13,16 @@ public enum ErrorMessage { */ USER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 유저는 존재하지 않습니다."), REFRESH_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 유저의 리프레시 토큰이 존재하지 않습니다."), + MOIM_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 글모임이 존재하지 않습니다."), + CONTENT_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 모임의 주제가 존재하지 않습니다."), + HANDLER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "요청하신 URL은 정보가 없습니다."), /* Bad Request */ ENUM_VALUE_BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "요청한 값이 유효하지 않습니다."), AUTHENTICATION_CODE_EXPIRED(HttpStatus.BAD_REQUEST.value(), "인가 코드가 만료되었습니다."), SOCIAL_TYPE_BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "로그인 요청이 유효하지 않습니다."), + BEARER_LOST_ERROR(HttpStatus.BAD_REQUEST.value(), "토큰의 요청에 Bearer이 담겨 있지 않습니다."), /* Unauthorized */ @@ -26,6 +30,10 @@ public enum ErrorMessage { TOKEN_INCORRECT_ERROR(HttpStatus.UNAUTHORIZED.value(), "리프레시 토큰이 유효하지 않습니다."), TOKEN_VALIDATION_ERROR(HttpStatus.UNAUTHORIZED.value(), "사용자 검증 토큰이 유효하지 안습니다."), /* + Forbidden + */ + USER_AUTHENTICATE_ERROR(HttpStatus.FORBIDDEN.value(), "해당 사용자는 모임에 접근 권한이 없습니다."), + /* Internal Server Error */ INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "서버 내부 오류입니다."); diff --git a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java index d4ae4aca..4ec7d2f5 100644 --- a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java @@ -10,7 +10,9 @@ public enum SuccessMessage { LOGIN_SUCCESS(HttpStatus.OK.value(), "소셜 로그인이 완료되었습니다."), ISSUE_ACCESS_TOKEN_SUCCESS(HttpStatus.OK.value(), "액세스 토큰 재발급이 완료되었습니다."), USER_DELETE_SUCCESS(HttpStatus.OK.value(), "회원 삭제가 완료되었습니다."), - LOGOUT_SUCCESS(HttpStatus.OK.value(), "로그아웃이 완료되었습니다.") + LOGOUT_SUCCESS(HttpStatus.OK.value(), "로그아웃이 완료되었습니다."), + + TOPIC_SEARCH_SUCCESS(HttpStatus.OK.value(), "주제 조회가 완료되었습니다."), ; int status; diff --git a/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java b/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java new file mode 100644 index 00000000..629c8f74 --- /dev/null +++ b/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java @@ -0,0 +1,9 @@ +package com.mile.exception.model; + +import com.mile.exception.message.ErrorMessage; + +public class ForbiddenException extends MileException { + public ForbiddenException(final ErrorMessage errorMessage) { + super(errorMessage); + } +} diff --git a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java index 154adebd..cc3046f3 100644 --- a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import com.mile.dto.ErrorResponse; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; +import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.JwtValidationException; import com.mile.exception.model.NotFoundException; import com.mile.exception.model.UnauthorizedException; @@ -13,6 +14,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.NoHandlerFoundException; @Slf4j @RestControllerAdvice @@ -38,11 +40,21 @@ public ResponseEntity handleJwtValidationException(final JwtValid return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ErrorResponse.of(e.getErrorMessage())); } + @ExceptionHandler(ForbiddenException.class) + public ResponseEntity handleForbiddenException(final UnauthorizedException e) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ErrorResponse.of(e.getErrorMessage())); + } + @ExceptionHandler(NotFoundException.class) public ResponseEntity handleNotFoundException(final NotFoundException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of(e.getErrorMessage())); } + @ExceptionHandler({NoHandlerFoundException.class}) + public ResponseEntity handleNoHandlerFoundException(final NoHandlerFoundException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of(ErrorMessage.HANDLER_NOT_FOUND)); + } + @ExceptionHandler(Exception.class) protected ResponseEntity handleException(final Exception error, final HttpServletRequest request) { log.error("================================================NEW==============================================="); From 80f8357b15b961d51810f9c3119151f8b796813c Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:21:50 +0900 Subject: [PATCH 16/29] #18 [feat] pen -> writer --- .../mile/penNameProfile/serivce/PenNameProfileService.java | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java diff --git a/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java b/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java deleted file mode 100644 index 1622f9d5..00000000 --- a/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mile.penNameProfile.serivce; - -import org.springframework.stereotype.Service; - -@Service -public class PenNameProfileService { -} From 745cac213ee155f9a4f8aef9e2cb11f153374908 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:23:04 +0900 Subject: [PATCH 17/29] =?UTF-8?q?#18=20[feat]=20Security=20Config=20WHITE?= =?UTF-8?q?=20LIST=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/mile/config/security/SecurityConfig.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java index b7896897..ff9e7945 100644 --- a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java +++ b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java @@ -24,8 +24,9 @@ public class SecurityConfig { private static final String[] AUTH_WHITELIST = { - "/user/login", - "/user/token-refresh", + "/api/user/login", + "/api/user/token-refresh", + "/api/**", "/actuator/health", "/v3/api-docs/**", "/swagger-ui/**", From 278cd22f7b622e4f3aa8c46e33a85147dcd1208d Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:23:57 +0900 Subject: [PATCH 18/29] =?UTF-8?q?#18=20[feat]=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20getter=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?topic=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=B3=80=EA=B2=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/mile/config/BaseTimeEntity.java | 3 +++ module-domain/src/main/java/com/mile/post/Post.java | 3 ++- .../src/main/java/com/mile/topic/domain/Topic.java | 9 ++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java b/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java index 9d958a42..1d4cc793 100644 --- a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java +++ b/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java @@ -3,9 +3,12 @@ import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; import java.time.LocalDateTime; + +import lombok.Getter; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; +@Getter @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public abstract class BaseTimeEntity { diff --git a/module-domain/src/main/java/com/mile/post/Post.java b/module-domain/src/main/java/com/mile/post/Post.java index d5cd3ffd..2f946d33 100644 --- a/module-domain/src/main/java/com/mile/post/Post.java +++ b/module-domain/src/main/java/com/mile/post/Post.java @@ -1,5 +1,6 @@ package com.mile.post; +import com.mile.config.BaseTimeEntity; import com.mile.topic.domain.Topic; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -8,7 +9,7 @@ import jakarta.persistence.ManyToOne; @Entity -public class Post { +public class Post extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/module-domain/src/main/java/com/mile/topic/domain/Topic.java b/module-domain/src/main/java/com/mile/topic/domain/Topic.java index 5a0757af..027b1a9f 100644 --- a/module-domain/src/main/java/com/mile/topic/domain/Topic.java +++ b/module-domain/src/main/java/com/mile/topic/domain/Topic.java @@ -1,14 +1,17 @@ package com.mile.topic.domain; +import com.mile.config.BaseTimeEntity; import com.mile.moim.domain.Moim; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import lombok.Getter; @Entity -public class Topic { +@Getter +public class Topic extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -16,7 +19,7 @@ public class Topic { @ManyToOne private Moim moim; + private String keyword; private String topic; - private int week; - private boolean isClosed; + private String description; } From c9719bacdc72b2713189cf0c55571d7f6f303a80 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:24:15 +0900 Subject: [PATCH 19/29] =?UTF-8?q?#18=20[feat]=20=EA=B8=80=EA=B0=90=20List?= =?UTF-8?q?=20=EB=B0=98=ED=99=98=20API=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mile/moim/repository/MoimRepository.java | 7 +++ .../com/mile/moim/serivce/MoimService.java | 26 ++++++++++ .../topic/repository/TopicRepository.java | 11 +++++ .../com/mile/topic/serivce/TopicService.java | 47 +++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java create mode 100644 module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java diff --git a/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java b/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java new file mode 100644 index 00000000..b52ac9c8 --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java @@ -0,0 +1,7 @@ +package com.mile.moim.repository; + +import com.mile.moim.domain.Moim; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MoimRepository extends JpaRepository { +} diff --git a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java index aa140403..da62f36b 100644 --- a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java @@ -1,7 +1,33 @@ package com.mile.moim.serivce; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.UnauthorizedException; +import com.mile.moim.serivce.dto.ContentListResponse; +import com.mile.topic.serivce.TopicService; +import com.mile.writerName.serivce.WriterNameService; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class MoimService { + private final WriterNameService penNameService; + private final TopicService topicService; + + public ContentListResponse getContentsFromMoim( + final Long moimId, + final Long userId + ) { + authenticateUserOfMoim(moimId, userId); + return ContentListResponse.of(topicService.getContentsFromMoim(moimId)); + } + + private void authenticateUserOfMoim( + final Long moimId, + final Long userId + ) { + if (!penNameService.isUserInMoim(moimId, userId)) { + throw new UnauthorizedException(ErrorMessage.USER_AUTHENTICATE_ERROR); + } + } } diff --git a/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java new file mode 100644 index 00000000..72e678df --- /dev/null +++ b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java @@ -0,0 +1,11 @@ +package com.mile.topic.repository; + +import com.mile.topic.domain.Topic; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface TopicRepository extends JpaRepository { + + public List findByMoimId(final Long moimId); +} diff --git a/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java b/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java index 70b6e999..7556e30e 100644 --- a/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java +++ b/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java @@ -1,7 +1,54 @@ package com.mile.topic.serivce; +import com.mile.config.BaseTimeEntity; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.NotFoundException; +import com.mile.topic.domain.Topic; +import com.mile.topic.repository.TopicRepository; +import com.mile.topic.serivce.dto.ContentResponse; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + @Service +@RequiredArgsConstructor public class TopicService { + + private final TopicRepository topicRepository; + + public List getContentsFromMoim( + final Long moimId + ) { + List topicList = sortByCreatedAt(findByMoimId(moimId)); + isContentsEmpty(topicList); + return topicList + .stream() + .map(ContentResponse::of) + .collect(Collectors.toList()); + } + + private void isContentsEmpty( + final List topicList + ) { + if (topicList.isEmpty()) { + throw new NotFoundException(ErrorMessage.CONTENT_NOT_FOUND); + } + } + + private List findByMoimId( + final Long moimId + ) { + return topicRepository.findByMoimId(moimId); + } + + private List sortByCreatedAt( + final List topicList + ) { + return topicList.stream() + .sorted(Comparator.comparing(BaseTimeEntity::getCreatedAt)) + .collect(Collectors.toList()); + } } From 917ce3c0122f6bcea6a7d22e5580dd0fdfa419ed Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:24:28 +0900 Subject: [PATCH 20/29] =?UTF-8?q?#18=20[feat]=20bearer=20+=20=EC=9D=B4=20?= =?UTF-8?q?=EC=95=84=EB=8B=90=20=EB=95=8C=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/mile/filter/JwtAuthenticationFilter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java index 3a14f1a4..2bcf9b1f 100644 --- a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java +++ b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java @@ -2,6 +2,7 @@ import com.mile.authentication.UserAuthentication; import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.BadRequestException; import com.mile.exception.model.JwtValidationException; import com.mile.jwt.JwtTokenProvider; import com.mile.jwt.JwtValidationType; @@ -49,7 +50,8 @@ private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring("Bearer ".length()); + } else { + throw new BadRequestException(ErrorMessage.BEARER_LOST_ERROR); } - return null; } } \ No newline at end of file From 5e2519d700addcee25f6bae9fb43735227fb1440 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:26:41 +0900 Subject: [PATCH 21/29] =?UTF-8?q?#18=20[feat]=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/mile/handler/GlobalExceptionHandler.java | 2 +- .../src/main/java/com/mile/moim/serivce/MoimService.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java index cc3046f3..3d5d564c 100644 --- a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java @@ -41,7 +41,7 @@ public ResponseEntity handleJwtValidationException(final JwtValid } @ExceptionHandler(ForbiddenException.class) - public ResponseEntity handleForbiddenException(final UnauthorizedException e) { + public ResponseEntity handleForbiddenException(final ForbiddenException e) { return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ErrorResponse.of(e.getErrorMessage())); } diff --git a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java index da62f36b..c5bc84f8 100644 --- a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java @@ -1,6 +1,7 @@ package com.mile.moim.serivce; import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.UnauthorizedException; import com.mile.moim.serivce.dto.ContentListResponse; import com.mile.topic.serivce.TopicService; @@ -27,7 +28,7 @@ private void authenticateUserOfMoim( final Long userId ) { if (!penNameService.isUserInMoim(moimId, userId)) { - throw new UnauthorizedException(ErrorMessage.USER_AUTHENTICATE_ERROR); + throw new ForbiddenException(ErrorMessage.USER_AUTHENTICATE_ERROR); } } } From 14cccfefd3b04643df2b211ea06f4b021fd7dc37 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sat, 6 Jan 2024 23:37:25 +0900 Subject: [PATCH 22/29] #18 [feat] moim controller swagger --- .../src/main/java/com/mile/controller/moim/MoimController.java | 3 ++- .../src/main/java/com/mile/config/security/SecurityConfig.java | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java index 198f8acf..7a791bb1 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimController.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -15,11 +15,12 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/moim") -public class MoimController { +public class MoimController implements MoimControllerSwagger { private final MoimService moimService; @GetMapping("/{moimId}") + @Override public SuccessResponse getTopicsFromMoim( @PathVariable final Long moimId, final Principal principal diff --git a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java index ff9e7945..0b6f4e1a 100644 --- a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java +++ b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java @@ -24,8 +24,6 @@ public class SecurityConfig { private static final String[] AUTH_WHITELIST = { - "/api/user/login", - "/api/user/token-refresh", "/api/**", "/actuator/health", "/v3/api-docs/**", From 7ff4745f846bbc82a1823b06ee2e67ad49933ee5 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 7 Jan 2024 09:36:06 +0900 Subject: [PATCH 23/29] =?UTF-8?q?#18=20[feat]=20filter=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/mile/controller/moim/MoimController.java | 3 +-- .../main/java/com/mile/filter/JwtAuthenticationFilter.java | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java index 7a791bb1..198f8acf 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimController.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -15,12 +15,11 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/moim") -public class MoimController implements MoimControllerSwagger { +public class MoimController { private final MoimService moimService; @GetMapping("/{moimId}") - @Override public SuccessResponse getTopicsFromMoim( @PathVariable final Long moimId, final Principal principal diff --git a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java index 2bcf9b1f..a92f7461 100644 --- a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java +++ b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java @@ -11,6 +11,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.lang.NonNull; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; @@ -21,6 +22,7 @@ import java.io.IOException; @Component +@Slf4j @RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter { @@ -50,8 +52,9 @@ private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring("Bearer ".length()); - } else { + } else if (StringUtils.hasText(bearerToken) && !bearerToken.startsWith("Bearer ")) { throw new BadRequestException(ErrorMessage.BEARER_LOST_ERROR); } + return null; } } \ No newline at end of file From 51c8b23c6f1ce63adbd7bfe56e5dd110c0512f5f Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 7 Jan 2024 09:47:28 +0900 Subject: [PATCH 24/29] =?UTF-8?q?#18=20[feat]=20swagger=20success=20respon?= =?UTF-8?q?se=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mile/controller/moim/MoimControllerSwagger.java | 9 +++++---- .../com/mile/controller/user/UserControllerSwagger.java | 9 ++++----- .../java/com/mile/filter/JwtAuthenticationFilter.java | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java index d1b6110a..34ebf734 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java @@ -18,10 +18,11 @@ public interface MoimControllerSwagger { @Operation(summary = "에디터 상단 글감 조회") @ApiResponses( value = { - @ApiResponse(responseCode = "200", description = "글감 조회가 완료되었습니다.", - content = @Content(schema = @Schema(implementation = SuccessResponse.class))), - @ApiResponse(responseCode = "403", description = "해당 사용자는 모임에 접근 권한이 없습니다."), - @ApiResponse(responseCode = "404", description = "해당 모임의 주제가 존재하지 않습니다."), + @ApiResponse(responseCode = "200", description = "글감 조회가 완료되었습니다."), + @ApiResponse(responseCode = "403", description = "해당 사용자는 모임에 접근 권한이 없습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "404", description = "해당 모임의 주제가 존재하지 않습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } diff --git a/module-api/src/main/java/com/mile/controller/user/UserControllerSwagger.java b/module-api/src/main/java/com/mile/controller/user/UserControllerSwagger.java index 0ecf3dad..db77dad2 100644 --- a/module-api/src/main/java/com/mile/controller/user/UserControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/user/UserControllerSwagger.java @@ -21,8 +21,7 @@ public interface UserControllerSwagger { @Operation(summary = "소셜 로그인") @ApiResponses( value = { - @ApiResponse(responseCode = "200", description = "소셜 로그인이 완료되었습니다.", - content = @Content(schema = @Schema(implementation = SuccessResponse.class))), + @ApiResponse(responseCode = "200", description = "소셜 로그인이 완료되었습니다."), @ApiResponse(responseCode = "400", description = "1. 요청한 값이 유효하지 않습니다.\n" + "2. 인가 코드가 만료되었습니다.\n", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @@ -38,7 +37,7 @@ SuccessResponse login( @Operation(summary = "액세스 토큰 재발급") @ApiResponses( value = { - @ApiResponse(responseCode = "200", description = "액세스 토큰 재발급이 완료되었습니다.", content = @Content(schema = @Schema(implementation = SuccessResponse.class))), + @ApiResponse(responseCode = "200", description = "액세스 토큰 재발급이 완료되었습니다."), @ApiResponse(responseCode = "401", description = "리프레시 토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @ApiResponse(responseCode = "404", description = "해당 유저의 리프레시 토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) @@ -51,7 +50,7 @@ SuccessResponse refreshToken( @Operation(summary = "회원 탈퇴") @ApiResponses( value = { - @ApiResponse(responseCode = "200", description = "회원 삭제가 완료되었습니다.", content = @Content(schema = @Schema(implementation = SuccessResponse.class))), + @ApiResponse(responseCode = "200", description = "회원 삭제가 완료되었습니다."), @ApiResponse(responseCode = "404", description = "1. 해당 유저의 리프레시 토큰이 존재하지 않습니다.\n" + "2. 해당 유저는 존재하지 않습니다.", @@ -66,7 +65,7 @@ SuccessResponse deleteUser( @Operation(summary = "로그아웃") @ApiResponses( value = { - @ApiResponse(responseCode = "200", description = "로그아웃이 완료되었습니다.", content = @Content(schema = @Schema(implementation = SuccessResponse.class))), + @ApiResponse(responseCode = "200", description = "로그아웃이 완료되었습니다."), @ApiResponse(responseCode = "404", description = "해당 유저의 리프레시 토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } diff --git a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java index cc5a8419..a92f7461 100644 --- a/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java +++ b/module-common/src/main/java/com/mile/filter/JwtAuthenticationFilter.java @@ -55,5 +55,6 @@ private String getJwtFromRequest(HttpServletRequest request) { } else if (StringUtils.hasText(bearerToken) && !bearerToken.startsWith("Bearer ")) { throw new BadRequestException(ErrorMessage.BEARER_LOST_ERROR); } + return null; } } \ No newline at end of file From 75033570ee9d2c29f43d7eefd3c4b6e1891db86a Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 7 Jan 2024 10:51:56 +0900 Subject: [PATCH 25/29] #18 [feat] penName -> writerName --- .../src/main/java/com/mile/moim/serivce/MoimService.java | 5 ++--- .../java/com/mile/writerName/serivce/WriterNameService.java | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java index c5bc84f8..a403d643 100644 --- a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java @@ -2,7 +2,6 @@ import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.ForbiddenException; -import com.mile.exception.model.UnauthorizedException; import com.mile.moim.serivce.dto.ContentListResponse; import com.mile.topic.serivce.TopicService; import com.mile.writerName.serivce.WriterNameService; @@ -12,7 +11,7 @@ @Service @RequiredArgsConstructor public class MoimService { - private final WriterNameService penNameService; + private final WriterNameService writerNameService; private final TopicService topicService; public ContentListResponse getContentsFromMoim( @@ -27,7 +26,7 @@ private void authenticateUserOfMoim( final Long moimId, final Long userId ) { - if (!penNameService.isUserInMoim(moimId, userId)) { + if (!writerNameService.isUserInMoim(moimId, userId)) { throw new ForbiddenException(ErrorMessage.USER_AUTHENTICATE_ERROR); } } diff --git a/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java index 937a10d6..5e774360 100644 --- a/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java +++ b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java @@ -7,13 +7,13 @@ @Service @RequiredArgsConstructor public class WriterNameService { - private final WriterNameRepository penNameRepository; + private final WriterNameRepository writerNameRepository; public boolean isUserInMoim( final Long moimId, final Long writerId ) { - return penNameRepository.findByMoimIdAndWriterId(moimId, writerId).isPresent(); + return writerNameRepository.findByMoimIdAndWriterId(moimId, writerId).isPresent(); } } From 8fea34df8bc01846432d432d92ebe7a780efbf6d Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 7 Jan 2024 13:37:46 +0900 Subject: [PATCH 26/29] =?UTF-8?q?#20=20[feat]=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20API=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mile/controller/post/PostController.java | 38 ++++++++++++++++++ .../post/PostControllerSwagger.java | 40 +++++++++++++++++++ .../mile/config/security/SecurityConfig.java | 3 +- .../main/java/com/mile/dto/ErrorResponse.java | 4 ++ .../mile/exception/message/ErrorMessage.java | 7 ++++ .../exception/message/SuccessMessage.java | 8 +++- .../mile/handler/GlobalExceptionHandler.java | 15 +++++++ module-domain/build.gradle | 3 ++ 8 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 module-api/src/main/java/com/mile/controller/post/PostController.java create mode 100644 module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java diff --git a/module-api/src/main/java/com/mile/controller/post/PostController.java b/module-api/src/main/java/com/mile/controller/post/PostController.java new file mode 100644 index 00000000..788c1736 --- /dev/null +++ b/module-api/src/main/java/com/mile/controller/post/PostController.java @@ -0,0 +1,38 @@ +package com.mile.controller.post; + +import com.mile.dto.SuccessResponse; +import com.mile.exception.message.SuccessMessage; +import com.mile.post.service.PostService; +import com.mile.post.service.dto.CommentCreateRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; + +@RestController +@RequestMapping("/api/post") +@RequiredArgsConstructor +public class PostController implements PostControllerSwagger{ + + private final PostService postService; + + @PostMapping("/{postId}/comment") + @Override + public SuccessResponse postComment( + @PathVariable final Long postId, + @Valid @RequestBody final CommentCreateRequest commentCreateRequest, + final Principal principal + ) { + postService.createCommentOnPost( + postId, + Long.valueOf(principal.getName()), + commentCreateRequest + ); + return SuccessResponse.of(SuccessMessage.COMMENT_CREATE_SUCCESS); + } +} diff --git a/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java b/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java new file mode 100644 index 00000000..0bc6b3ae --- /dev/null +++ b/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java @@ -0,0 +1,40 @@ +package com.mile.controller.post; + +import com.mile.dto.ErrorResponse; +import com.mile.dto.SuccessResponse; +import com.mile.post.service.dto.CommentCreateRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; + +import java.security.Principal; + +@Tag(name = "Post", description = "게시글 관련 API - 댓글 등록/ 조회 포함") +public interface PostControllerSwagger { + + @Operation(summary = "댓글 작성") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "댓글 등록이 완료되었습니다."), + @ApiResponse(responseCode = "400", + description = "1. 댓글 최대 입력 길이(500자)를 초과하였습니다.\n" + + "2.댓글에 내용이 없습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "403", description = "해당 사용자는 모임에 접근 권한이 없습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + SuccessResponse postComment( + @PathVariable final Long postId, + @Valid @RequestBody final CommentCreateRequest commentCreateRequest, + final Principal principal + ); +} diff --git a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java index b7896897..0b6f4e1a 100644 --- a/module-common/src/main/java/com/mile/config/security/SecurityConfig.java +++ b/module-common/src/main/java/com/mile/config/security/SecurityConfig.java @@ -24,8 +24,7 @@ public class SecurityConfig { private static final String[] AUTH_WHITELIST = { - "/user/login", - "/user/token-refresh", + "/api/**", "/actuator/health", "/v3/api-docs/**", "/swagger-ui/**", diff --git a/module-common/src/main/java/com/mile/dto/ErrorResponse.java b/module-common/src/main/java/com/mile/dto/ErrorResponse.java index 659506f4..785f6a4f 100644 --- a/module-common/src/main/java/com/mile/dto/ErrorResponse.java +++ b/module-common/src/main/java/com/mile/dto/ErrorResponse.java @@ -9,4 +9,8 @@ public record ErrorResponse( public static ErrorResponse of(final ErrorMessage errorMessage) { return new ErrorResponse(errorMessage.getStatus(), errorMessage.getMessage()); } + + public static ErrorResponse of(final int status, final String message) { + return new ErrorResponse(status, message); + } } diff --git a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java index 1c1ccc11..2ddf47a8 100644 --- a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java @@ -13,12 +13,14 @@ public enum ErrorMessage { */ USER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 유저는 존재하지 않습니다."), REFRESH_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 유저의 리프레시 토큰이 존재하지 않습니다."), + POST_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 글은 존재하지 않습니다."), /* Bad Request */ ENUM_VALUE_BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "요청한 값이 유효하지 않습니다."), AUTHENTICATION_CODE_EXPIRED(HttpStatus.BAD_REQUEST.value(), "인가 코드가 만료되었습니다."), SOCIAL_TYPE_BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "로그인 요청이 유효하지 않습니다."), + VALIDATION_REQUEST_MISSING_EXCEPTION(HttpStatus.BAD_REQUEST.value(), "요청 값이 유효하지 않습니다."), /* Unauthorized */ @@ -26,6 +28,11 @@ public enum ErrorMessage { TOKEN_INCORRECT_ERROR(HttpStatus.UNAUTHORIZED.value(), "리프레시 토큰이 유효하지 않습니다."), TOKEN_VALIDATION_ERROR(HttpStatus.UNAUTHORIZED.value(), "사용자 검증 토큰이 유효하지 안습니다."), /* + Forbidden + */ + USER_AUTHENTICATE_ERROR(HttpStatus.FORBIDDEN.value(), "해당 사용자는 모임에 접근 권한이 없습니다."), + /* + /* Internal Server Error */ INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "서버 내부 오류입니다."); diff --git a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java index d4ae4aca..42c6f169 100644 --- a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java @@ -10,7 +10,13 @@ public enum SuccessMessage { LOGIN_SUCCESS(HttpStatus.OK.value(), "소셜 로그인이 완료되었습니다."), ISSUE_ACCESS_TOKEN_SUCCESS(HttpStatus.OK.value(), "액세스 토큰 재발급이 완료되었습니다."), USER_DELETE_SUCCESS(HttpStatus.OK.value(), "회원 삭제가 완료되었습니다."), - LOGOUT_SUCCESS(HttpStatus.OK.value(), "로그아웃이 완료되었습니다.") + LOGOUT_SUCCESS(HttpStatus.OK.value(), "로그아웃이 완료되었습니다."), + + /* + 201 CREATED + */ + COMMENT_CREATE_SUCCESS(HttpStatus.CREATED.value(), "댓글 등록이 완료되었습니다."), + ; int status; diff --git a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java index 154adebd..930a5ce3 100644 --- a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import com.mile.dto.ErrorResponse; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.BadRequestException; +import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.JwtValidationException; import com.mile.exception.model.NotFoundException; import com.mile.exception.model.UnauthorizedException; @@ -11,6 +12,8 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -38,6 +41,18 @@ public ResponseEntity handleJwtValidationException(final JwtValid return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ErrorResponse.of(e.getErrorMessage())); } + @ExceptionHandler(MethodArgumentNotValidException.class) + protected ResponseEntity handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { + FieldError fieldError = e.getBindingResult().getFieldError(); + if (fieldError == null) return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(ErrorMessage.VALIDATION_REQUEST_MISSING_EXCEPTION)); + else return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(HttpStatus.BAD_REQUEST.value(), fieldError.getDefaultMessage())); + } + + @ExceptionHandler(ForbiddenException.class) + public ResponseEntity handleForbiddenException(final ForbiddenException e) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ErrorResponse.of(e.getErrorMessage())); + } + @ExceptionHandler(NotFoundException.class) public ResponseEntity handleNotFoundException(final NotFoundException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of(e.getErrorMessage())); diff --git a/module-domain/build.gradle b/module-domain/build.gradle index 79e7fd48..dc293c35 100644 --- a/module-domain/build.gradle +++ b/module-domain/build.gradle @@ -5,6 +5,9 @@ dependencies { implementation project(':module-auth') implementation project(':module-common') + //Swagger + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' + // QueryDSL Implementation implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" From 1f768c4b8432538bad91043beac40a6e30553514 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 7 Jan 2024 13:38:19 +0900 Subject: [PATCH 27/29] #20 [refactor] penName -> writerName --- .../domain/WriterName.java} | 4 ++-- .../repository/WriterNameRepository.java | 11 +++++++++++ .../writerName/serivce/WriterNameService.java | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) rename module-domain/src/main/java/com/mile/{penNameProfile/domain/PenName.java => writerName/domain/WriterName.java} (88%) create mode 100644 module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java create mode 100644 module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java diff --git a/module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java b/module-domain/src/main/java/com/mile/writerName/domain/WriterName.java similarity index 88% rename from module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java rename to module-domain/src/main/java/com/mile/writerName/domain/WriterName.java index 435f1592..9d78de66 100644 --- a/module-domain/src/main/java/com/mile/penNameProfile/domain/PenName.java +++ b/module-domain/src/main/java/com/mile/writerName/domain/WriterName.java @@ -1,4 +1,4 @@ -package com.mile.penNameProfile.domain; +package com.mile.writerName.domain; import com.mile.moim.domain.Moim; import com.mile.user.domain.User; @@ -9,7 +9,7 @@ import jakarta.persistence.ManyToOne; @Entity -public class PenName { +public class WriterName { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java b/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java new file mode 100644 index 00000000..5cda835d --- /dev/null +++ b/module-domain/src/main/java/com/mile/writerName/repository/WriterNameRepository.java @@ -0,0 +1,11 @@ +package com.mile.writerName.repository; + +import com.mile.writerName.domain.WriterName; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface WriterNameRepository extends JpaRepository { + + Optional findByMoimIdAndWriterId(final Long moimId, final Long userId); +} \ No newline at end of file diff --git a/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java new file mode 100644 index 00000000..5e774360 --- /dev/null +++ b/module-domain/src/main/java/com/mile/writerName/serivce/WriterNameService.java @@ -0,0 +1,19 @@ +package com.mile.writerName.serivce; + +import com.mile.writerName.repository.WriterNameRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class WriterNameService { + private final WriterNameRepository writerNameRepository; + + public boolean isUserInMoim( + final Long moimId, + final Long writerId + ) { + return writerNameRepository.findByMoimIdAndWriterId(moimId, writerId).isPresent(); + } + +} From 965c4d7b68a167f95e1bb8e90479ed7701faf151 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 7 Jan 2024 13:38:52 +0900 Subject: [PATCH 28/29] =?UTF-8?q?#20=20[feat]=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/mile/comment/domain/Comment.java | 25 ++++++++++++++++++- .../main/java/com/mile/moim/domain/Moim.java | 2 ++ .../com/mile/moim/serivce/MoimService.java | 16 ++++++++++++ .../serivce/PenNameProfileService.java | 7 ------ .../java/com/mile/post/{ => domain}/Post.java | 4 ++- .../java/com/mile/topic/domain/Topic.java | 9 ++++--- 6 files changed, 51 insertions(+), 12 deletions(-) delete mode 100644 module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java rename module-domain/src/main/java/com/mile/post/{ => domain}/Post.java (90%) diff --git a/module-domain/src/main/java/com/mile/comment/domain/Comment.java b/module-domain/src/main/java/com/mile/comment/domain/Comment.java index 27140d63..3c63d1e2 100644 --- a/module-domain/src/main/java/com/mile/comment/domain/Comment.java +++ b/module-domain/src/main/java/com/mile/comment/domain/Comment.java @@ -1,15 +1,23 @@ package com.mile.comment.domain; import com.mile.config.BaseTimeEntity; -import com.mile.post.Post; +import com.mile.post.domain.Post; +import com.mile.post.service.dto.CommentCreateRequest; import com.mile.user.domain.User; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; @Entity +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor public class Comment extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -23,4 +31,19 @@ public class Comment extends BaseTimeEntity { @ManyToOne private User user; + + public static Comment create( + final Post post, + final User user, + final CommentCreateRequest createRequest, + final boolean anonymous + ) { + return Comment + .builder() + .post(post) + .content(createRequest.content()) + .user(user) + .anonymous(anonymous) + .build(); + } } diff --git a/module-domain/src/main/java/com/mile/moim/domain/Moim.java b/module-domain/src/main/java/com/mile/moim/domain/Moim.java index 981b5fed..acadee6c 100644 --- a/module-domain/src/main/java/com/mile/moim/domain/Moim.java +++ b/module-domain/src/main/java/com/mile/moim/domain/Moim.java @@ -7,8 +7,10 @@ import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; +import lombok.Getter; @Entity +@Getter public class Moim { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java index aa140403..8b455303 100644 --- a/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/serivce/MoimService.java @@ -1,7 +1,23 @@ package com.mile.moim.serivce; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.ForbiddenException; +import com.mile.writerName.serivce.WriterNameService; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class MoimService { + private final WriterNameService writerNameService; + + + public void authenticateUserOfMoim( + final Long moimId, + final Long userId + ) { + if (!writerNameService.isUserInMoim(moimId, userId)) { + throw new ForbiddenException(ErrorMessage.USER_AUTHENTICATE_ERROR); + } + } } diff --git a/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java b/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java deleted file mode 100644 index 1622f9d5..00000000 --- a/module-domain/src/main/java/com/mile/penNameProfile/serivce/PenNameProfileService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mile.penNameProfile.serivce; - -import org.springframework.stereotype.Service; - -@Service -public class PenNameProfileService { -} diff --git a/module-domain/src/main/java/com/mile/post/Post.java b/module-domain/src/main/java/com/mile/post/domain/Post.java similarity index 90% rename from module-domain/src/main/java/com/mile/post/Post.java rename to module-domain/src/main/java/com/mile/post/domain/Post.java index d5cd3ffd..87969bde 100644 --- a/module-domain/src/main/java/com/mile/post/Post.java +++ b/module-domain/src/main/java/com/mile/post/domain/Post.java @@ -1,4 +1,4 @@ -package com.mile.post; +package com.mile.post.domain; import com.mile.topic.domain.Topic; import jakarta.persistence.Entity; @@ -6,8 +6,10 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import lombok.Getter; @Entity +@Getter public class Post { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/module-domain/src/main/java/com/mile/topic/domain/Topic.java b/module-domain/src/main/java/com/mile/topic/domain/Topic.java index 5a0757af..e48a54b6 100644 --- a/module-domain/src/main/java/com/mile/topic/domain/Topic.java +++ b/module-domain/src/main/java/com/mile/topic/domain/Topic.java @@ -1,14 +1,17 @@ package com.mile.topic.domain; +import com.mile.config.BaseTimeEntity; import com.mile.moim.domain.Moim; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import lombok.Getter; @Entity -public class Topic { +@Getter +public class Topic extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -17,6 +20,6 @@ public class Topic { private Moim moim; private String topic; - private int week; - private boolean isClosed; + private String keyword; + private String description; } From c97dcf2388c4af4b0112810f6be464c401eace22 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 7 Jan 2024 13:39:09 +0900 Subject: [PATCH 29/29] =?UTF-8?q?#20=20[feat]=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/model/ForbiddenException.java | 9 ++++ .../comment/repository/CommentRepository.java | 7 +++ .../mile/comment/service/CommentService.java | 17 ++++++ .../java/com/mile/curious/domain/Curious.java | 2 +- .../mile/post/repository/PostRepository.java | 7 +++ .../com/mile/post/service/PostService.java | 52 +++++++++++++++++++ .../service/dto/CommentCreateRequest.java | 14 +++++ .../topic/repository/TopicRepository.java | 7 +++ .../com/mile/topic/serivce/TopicService.java | 14 +++++ .../com/mile/user/serivce/UserService.java | 9 ++++ 10 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 module-common/src/main/java/com/mile/exception/model/ForbiddenException.java create mode 100644 module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java create mode 100644 module-domain/src/main/java/com/mile/post/repository/PostRepository.java create mode 100644 module-domain/src/main/java/com/mile/post/service/PostService.java create mode 100644 module-domain/src/main/java/com/mile/post/service/dto/CommentCreateRequest.java create mode 100644 module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java diff --git a/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java b/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java new file mode 100644 index 00000000..6ca4f559 --- /dev/null +++ b/module-common/src/main/java/com/mile/exception/model/ForbiddenException.java @@ -0,0 +1,9 @@ +package com.mile.exception.model; + +import com.mile.exception.message.ErrorMessage; + +public class ForbiddenException extends MileException { + public ForbiddenException(final ErrorMessage errorMessage) { + super(errorMessage); + } +} \ No newline at end of file diff --git a/module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java b/module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java new file mode 100644 index 00000000..b6ec0570 --- /dev/null +++ b/module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java @@ -0,0 +1,7 @@ +package com.mile.comment.repository; + +import com.mile.comment.domain.Comment; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CommentRepository extends JpaRepository { +} diff --git a/module-domain/src/main/java/com/mile/comment/service/CommentService.java b/module-domain/src/main/java/com/mile/comment/service/CommentService.java index 4e2718cc..04dd34a4 100644 --- a/module-domain/src/main/java/com/mile/comment/service/CommentService.java +++ b/module-domain/src/main/java/com/mile/comment/service/CommentService.java @@ -1,7 +1,24 @@ package com.mile.comment.service; +import com.mile.comment.domain.Comment; +import com.mile.comment.repository.CommentRepository; +import com.mile.post.domain.Post; +import com.mile.post.service.dto.CommentCreateRequest; +import com.mile.user.domain.User; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class CommentService { + private static boolean ANONYMOUS_TRUE = true; + private final CommentRepository commentRepository; + + public void createComment( + final Post post, + final User user, + final CommentCreateRequest commentCreateRequest + ) { + commentRepository.save(Comment.create(post, user, commentCreateRequest, ANONYMOUS_TRUE)); + } } diff --git a/module-domain/src/main/java/com/mile/curious/domain/Curious.java b/module-domain/src/main/java/com/mile/curious/domain/Curious.java index d5726daf..2ef0fc93 100644 --- a/module-domain/src/main/java/com/mile/curious/domain/Curious.java +++ b/module-domain/src/main/java/com/mile/curious/domain/Curious.java @@ -1,6 +1,6 @@ package com.mile.curious.domain; -import com.mile.post.Post; +import com.mile.post.domain.Post; import com.mile.config.BaseTimeEntity; import com.mile.user.domain.User; import jakarta.persistence.Entity; diff --git a/module-domain/src/main/java/com/mile/post/repository/PostRepository.java b/module-domain/src/main/java/com/mile/post/repository/PostRepository.java new file mode 100644 index 00000000..ba2a267d --- /dev/null +++ b/module-domain/src/main/java/com/mile/post/repository/PostRepository.java @@ -0,0 +1,7 @@ +package com.mile.post.repository; + +import com.mile.post.domain.Post; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PostRepository extends JpaRepository { +} diff --git a/module-domain/src/main/java/com/mile/post/service/PostService.java b/module-domain/src/main/java/com/mile/post/service/PostService.java new file mode 100644 index 00000000..60ee49c3 --- /dev/null +++ b/module-domain/src/main/java/com/mile/post/service/PostService.java @@ -0,0 +1,52 @@ +package com.mile.post.service; + +import com.mile.comment.service.CommentService; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.NotFoundException; +import com.mile.post.domain.Post; +import com.mile.post.repository.PostRepository; +import com.mile.post.service.dto.CommentCreateRequest; +import com.mile.topic.serivce.TopicService; +import com.mile.user.serivce.UserService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class PostService { + + private final PostRepository postRepository; + private final TopicService topicService; + private final CommentService commentService; + private final UserService userService; + + @Transactional + public void createCommentOnPost( + final Long postId, + final Long userId, + final CommentCreateRequest commentCreateRequest + + ) { + Post post = findById(postId); + authenticateUserWithPost(post, userId); + commentService.createComment(post, userService.findById(userId), commentCreateRequest); + } + + + private void authenticateUserWithPost( + final Post post, + final Long userId + ) { + topicService.authenticateUserWithTopic(post.getTopic(), userId); + } + + public Post findById( + final Long postId + ) { + return postRepository.findById(postId) + .orElseThrow( + () -> new NotFoundException(ErrorMessage.POST_NOT_FOUND) + ); + } +} diff --git a/module-domain/src/main/java/com/mile/post/service/dto/CommentCreateRequest.java b/module-domain/src/main/java/com/mile/post/service/dto/CommentCreateRequest.java new file mode 100644 index 00000000..1b3e3436 --- /dev/null +++ b/module-domain/src/main/java/com/mile/post/service/dto/CommentCreateRequest.java @@ -0,0 +1,14 @@ +package com.mile.post.service.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record CommentCreateRequest( + + @Schema(description = "댓글 내용", example = "댓글 내용을 입력해주세요") + @NotBlank(message = "댓글에 내용이 없습니다.") + @Size(max = 500, message = "댓글 최대 입력 길이(500자)를 초과하였습니다.") + String content +) { +} diff --git a/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java new file mode 100644 index 00000000..f237a76f --- /dev/null +++ b/module-domain/src/main/java/com/mile/topic/repository/TopicRepository.java @@ -0,0 +1,7 @@ +package com.mile.topic.repository; + +import com.mile.topic.domain.Topic; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TopicRepository extends JpaRepository { +} diff --git a/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java b/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java index 70b6e999..df08bb2b 100644 --- a/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java +++ b/module-domain/src/main/java/com/mile/topic/serivce/TopicService.java @@ -1,7 +1,21 @@ package com.mile.topic.serivce; +import com.mile.moim.serivce.MoimService; +import com.mile.topic.domain.Topic; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class TopicService { + + private final MoimService moimService; + + public void authenticateUserWithTopic( + final Topic topic, + final Long userId + ) { + moimService.authenticateUserOfMoim(topic.getMoim().getId(), userId); + } + } diff --git a/module-domain/src/main/java/com/mile/user/serivce/UserService.java b/module-domain/src/main/java/com/mile/user/serivce/UserService.java index 5d4cd953..5833cb98 100644 --- a/module-domain/src/main/java/com/mile/user/serivce/UserService.java +++ b/module-domain/src/main/java/com/mile/user/serivce/UserService.java @@ -118,4 +118,13 @@ private LoginSuccessResponse getTokenDto( return getTokenByUserId(id); } } + + public User findById( + Long userId + ) { + return userRepository.findById(userId) + .orElseThrow( + () -> new NotFoundException(ErrorMessage.USER_NOT_FOUND) + ); + } }