Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] 윤한이형 피드백 반영 #67

Merged
merged 9 commits into from
Jan 17, 2024
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호 이렇게 API를 분리하는군요~ 신기하네요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.sopt.lequuServer.domain.book.controller;

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.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.sopt.lequuServer.domain.book.dto.request.BookCreateRequestDto;
import org.sopt.lequuServer.domain.book.dto.response.BookCreateResponseDto;
import org.sopt.lequuServer.domain.book.dto.response.BookDetailResponseDto;
import org.sopt.lequuServer.global.common.dto.ApiResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;

import java.security.Principal;

@Tag(name = "Book", description = "레큐북 API")
public interface BookApi {

@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "201",
description = "레큐북이 성공적으로 생성됐습니다.",
content = @Content(schema = @Schema(implementation = BookCreateResponseDto.class))
)
@Operation(summary = "레큐북 생성")
public ResponseEntity<ApiResponse<BookCreateResponseDto>> createBook(@Valid @RequestBody BookCreateRequestDto request, Principal principal);

@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "204",
description = "레큐북을 성공적으로 삭제했습니다."
)
@Operation(summary = "레큐북 삭제")
public ResponseEntity<?> deleteBook(@Schema(example = "1") @PathVariable Long bookId);

@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "레큐북 상세 조회에 성공했습니다.",
content = @Content(schema = @Schema(implementation = BookDetailResponseDto.class))
)
@Operation(summary = "레큐북 상세 조회")
public ResponseEntity<ApiResponse<BookDetailResponseDto>> getBookDetail(@Schema(example = "ee4f66f9-9cf4-4b28-90f4-f71d0ecba021") @PathVariable String bookUuid);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package org.sopt.lequuServer.domain.book.controller;

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.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.sopt.lequuServer.domain.book.dto.request.BookCreateRequestDto;
Expand All @@ -15,52 +10,31 @@
import org.sopt.lequuServer.global.common.dto.ApiResponse;
import org.sopt.lequuServer.global.exception.enums.SuccessType;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;

@RestController
@RequestMapping("/api/books")
@RequiredArgsConstructor
@Tag(name = "Book", description = "레큐북 API")
public class BookController {
public class BookController implements BookApi {

private final BookFacade bookFacade;

@PostMapping
@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "201",
description = "레큐북이 성공적으로 생성됐습니다.",
content = @Content(schema = @Schema(implementation = BookCreateResponseDto.class))
)
@ResponseStatus(HttpStatus.CREATED)
@Operation(summary = "레큐북 생성")
public ApiResponse<BookCreateResponseDto> createBook(@Valid @RequestBody BookCreateRequestDto request, Principal principal) {
return ApiResponse.success(SuccessType.CREATE_BOOK_SUCCESS, bookFacade.createBook(request, JwtProvider.getUserFromPrincial(principal)));
public ResponseEntity<ApiResponse<BookCreateResponseDto>> createBook(@Valid @RequestBody BookCreateRequestDto request, Principal principal) {
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(SuccessType.CREATE_BOOK_SUCCESS, bookFacade.createBook(request, JwtProvider.getUserFromPrincial(principal))));
}

@DeleteMapping("/{bookId}")
@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "204",
description = "레큐북을 성공적으로 삭제했습니다."
)
@Operation(summary = "레큐북 삭제")
public ApiResponse<?> deleteBook(@Schema(example = "1") @PathVariable Long bookId) {
public ResponseEntity<?> deleteBook(@PathVariable Long bookId) {
bookFacade.deleteBook(bookId);
return ApiResponse.success(SuccessType.DELETE_BOOK_SUCCESS);
return ResponseEntity.noContent().build();
}

@GetMapping("/detail/{bookUuid}")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "레큐북 상세 조회에 성공했습니다.",
content = @Content(schema = @Schema(implementation = BookDetailResponseDto.class))
)
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "레큐북 상세 조회")
public ApiResponse<BookDetailResponseDto> getBookDetail(@Schema(example = "ee4f66f9-9cf4-4b28-90f4-f71d0ecba021") @PathVariable String bookUuid) {
return ApiResponse.success(SuccessType.GET_BOOK_DETAIL_SUCCESS, bookFacade.getBookDetail(bookUuid));
public ResponseEntity<ApiResponse<BookDetailResponseDto>> getBookDetail(@PathVariable String bookUuid) {
return ResponseEntity.ok(ApiResponse.success(SuccessType.GET_BOOK_DETAIL_SUCCESS, bookFacade.getBookDetail(bookUuid)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ public record BookDetailResponseDto(
@Schema(description = "레큐 노트 개수", example = "100")
int noteNum,

List<NoteDetailResponseDto> noteList,
List<NoteDetailResponseDto> noteDetailDtos,

List<PostedStickerDetailResponseDto> postedStickerList
List<PostedStickerDetailResponseDto> postedStickerDetailDtos
) {
public static BookDetailResponseDto of(Book book) {
String bookDate = formatLocalDate(book);
Expand All @@ -57,22 +57,22 @@ public static BookDetailResponseDto of(Book book) {

// 레큐노트 리스트 가공
int renderTypeCounter = 1;
List<NoteDetailResponseDto> noteList = new ArrayList<>();
List<NoteDetailResponseDto> noteDetailDtos = new ArrayList<>();
for (Note note : sortedNotes) {
noteList.add(NoteDetailResponseDto.of(note, renderTypeCounter));
noteDetailDtos.add(NoteDetailResponseDto.of(note, renderTypeCounter));
renderTypeCounter = (renderTypeCounter % 6 == 0) ? 1 : renderTypeCounter + 1;
}

// 부착된 스티커 리스트 가공
List<PostedSticker> postedStickers = book.getPostedStickers();
List<PostedStickerDetailResponseDto> postedStickerList = new ArrayList<>();
List<PostedStickerDetailResponseDto> postedStickerDetailDtos = new ArrayList<>();
for (PostedSticker postedSticker : postedStickers) {
postedStickerList.add(PostedStickerDetailResponseDto.of(postedSticker));
postedStickerDetailDtos.add(PostedStickerDetailResponseDto.of(postedSticker));
}

return new BookDetailResponseDto(book.getId(), book.getFavoriteImage(), book.getFavoriteName(),
book.getTitle(), book.getDescription(), bookDate, book.getMember().getNickname(),
book.getBackgroundColor(), book.getNotes().size(), noteList, postedStickerList
book.getBackgroundColor(), book.getNotes().size(), noteDetailDtos, postedStickerDetailDtos
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ public BookCreateResponseDto createBook(BookCreateRequestDto request, Long membe
String bookUuid = UUID.randomUUID().toString();
// Presigned URL 이미지 업로드하기 위한 이미지 파일명 가져오기
// String imageUrl = s3Service.getURL(BOOK_FAVORITE_IMAGE_FOLDER_NAME.getValue() + request.favoriteImage());
String imageUrl = s3Service.getCloudFrontURL(
BOOK_FAVORITE_IMAGE_FOLDER_NAME.getValue() + request.favoriteImage());
String imageUrl = s3Service.getCloudFrontURL(BOOK_FAVORITE_IMAGE_FOLDER_NAME.getValue() + request.favoriteImage());

Book book = Book.builder()
.uuid(bookUuid)
Expand Down
15 changes: 0 additions & 15 deletions src/main/java/org/sopt/lequuServer/domain/book/model/Book.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,4 @@ public Book(String uuid, String favoriteName, String favoriteImage, String title
public static Book of(String uuid, String favoriteName, String favoriteImage, String title, String description, String backgroundColor, Member member, int popularRate) {
return new Book(uuid, favoriteName, favoriteImage, title, description, backgroundColor, member, popularRate);
}

// TODO S3 테스트용, 추후 삭제
public Book(String uuid, String favoriteName, String favoriteImage, String title, String description, String backgroundColor) {
this.uuid = uuid;
this.favoriteName = favoriteName;
this.favoriteImage = favoriteImage;
this.title = title;
this.description = description;
this.backgroundColor = backgroundColor;
}

// TODO S3 테스트용, 추후 삭제
public static Book test(String favoriteImage, String title) {
return new Book("test", "test", favoriteImage, title, "test", "#F5F5F5");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.sopt.lequuServer.domain.common.controller;

import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.sopt.lequuServer.domain.common.dto.response.PopularBookResponseDto;
import org.sopt.lequuServer.domain.common.dto.response.SplashDto;
import org.sopt.lequuServer.global.common.dto.ApiResponse;
import org.springframework.http.ResponseEntity;

import java.util.List;

@Tag(name = "Common", description = "홈 & 스플래시 API")
public interface CommonApi {

@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "스플래시 조회에 성공했습니다.",
content = @Content(schema = @Schema(implementation = SplashDto.class))
)
@Operation(summary = "스플래시 조회")
public ResponseEntity<ApiResponse<SplashDto>> getSplash();

@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "홈 화면 조회에 성공했습니다.",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = PopularBookResponseDto.class)))
)
@Operation(summary = "홈 조회")
public ResponseEntity<ApiResponse<List<PopularBookResponseDto>>> getHome();

@Hidden
public ResponseEntity<ApiResponse<?>> test();
}
Original file line number Diff line number Diff line change
@@ -1,62 +1,37 @@
package org.sopt.lequuServer.domain.common.controller;

import io.sentry.Sentry;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.sopt.lequuServer.domain.common.dto.response.PopularBookResponseDto;
import org.sopt.lequuServer.domain.common.dto.response.SplashDto;
import org.sopt.lequuServer.domain.common.facade.CommonFacade;
import org.sopt.lequuServer.global.common.dto.ApiResponse;
import org.sopt.lequuServer.global.exception.enums.SuccessType;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/common")
@Tag(name = "Common", description = "홈 & 스플래시 API")
public class CommonController {
public class CommonController implements CommonApi {

private final CommonFacade commonFacade;

@GetMapping("/splash")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "스플래시 조회에 성공했습니다.",
content = @Content(schema = @Schema(implementation = SplashDto.class))
)
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "스플래시 조회")
public ApiResponse<SplashDto> getSplash() {
return ApiResponse.success(SuccessType.GET_SPLASH_SUCCESS, commonFacade.getSplash());
public ResponseEntity<ApiResponse<SplashDto>> getSplash() {
return ResponseEntity.ok(ApiResponse.success(SuccessType.GET_SPLASH_SUCCESS, commonFacade.getSplash()));
}

@GetMapping("/home")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "홈 화면 조회에 성공했습니다.",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = PopularBookResponseDto.class)))
)
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "홈 조회")
public ApiResponse<List<PopularBookResponseDto>> getHome() {
return ApiResponse.success(SuccessType.GET_HOME_SUCCESS, commonFacade.getHome());
public ResponseEntity<ApiResponse<List<PopularBookResponseDto>>> getHome() {
return ResponseEntity.ok(ApiResponse.success(SuccessType.GET_HOME_SUCCESS, commonFacade.getHome()));
}

@Hidden
@GetMapping("/test")
@ResponseStatus(HttpStatus.OK)
public ApiResponse<?> test() {
public ResponseEntity<ApiResponse<?>> test() {
throw new RuntimeException("테스트용 에러 발생");
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.sopt.lequuServer.domain.member.controller;

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.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.sopt.lequuServer.domain.member.dto.request.MemberNicknameRequestDto;
import org.sopt.lequuServer.domain.member.dto.request.SocialLoginRequestDto;
import org.sopt.lequuServer.domain.member.dto.response.MemberLoginResponseDto;
import org.sopt.lequuServer.domain.member.dto.response.MemberNicknameResponseDto;
import org.sopt.lequuServer.domain.member.dto.response.MypageBookResponseDto;
import org.sopt.lequuServer.domain.member.dto.response.MypageNoteResponseDto;
import org.sopt.lequuServer.global.auth.jwt.TokenDto;
import org.sopt.lequuServer.global.common.dto.ApiResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;

import java.security.Principal;

@Tag(name = "Member", description = "마이페이지 & 로그인 관련 API")
public interface MemberApi {

@SecurityRequirement(name = "KAKAO Token")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "로그인에 성공했습니다.",
content = @Content(schema = @Schema(implementation = MemberLoginResponseDto.class))
)
@Operation(summary = "로그인 + 회원가입")
public ResponseEntity<ApiResponse<MemberLoginResponseDto>> login(
@Schema(description = "카카오 Access 토큰 (아래 박스에는 아무거나 입력)", example = "ZC57anP1qo58PNNJhKG1MBz9BImWMWih65gKPXKYAAABjQkwKSIh5oEAb4_jFQ")
@RequestHeader("Authorization") String socialAccessToken,
@RequestBody SocialLoginRequestDto request);


@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "Access 토큰 재발급에 성공했습니다.",
content = @Content(schema = @Schema(implementation = TokenDto.class))
)
@Operation(summary = "엑세스 토큰 재발급")
public ResponseEntity<ApiResponse<TokenDto>> reissue(
@Schema(description = "Refresh 토큰 (아래 박스에는 아무거나 입력)", example = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MDUyNTc0MDMsImV4cCI6MTc2ODMyOTQwMywibWVtYmVySWQiOjF9.qKP6AZc9EnA_6DLXJGHzURcJXlER8-mvUnPppEVCGfW4iyQGMS0ZT3f09K0khZBtEXHgMuyKy1m4K-GtSKtRAg")
@RequestHeader("Authorization") String refreshToken);

@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "로그아웃에 성공했습니다."
)
@Operation(summary = "로그아웃")
public ResponseEntity<ApiResponse<?>> logout(Principal principal);

@SecurityRequirement(name = "KAKAO Token")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "카카오 엑세스 토큰을 가져오는데 성공했습니다."
)
@Operation(summary = "카카오 엑세스 토큰 발급")
public ResponseEntity<ApiResponse<?>> kakaoAccessToken(
@Schema(description = "카카오 Authorization 코드 (아래 박스에는 아무거나 입력)", example = "u13t6n_uzDy3VbtRhvmtiOHIVioVMvFPTrrEK_lDgmd7-bY0GMD8FAi8TzUKPXNNAAABjQkwFpiSBpCp5rpDbg")
@RequestHeader("Authorization") String code);

@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "유저 닉네임을 설정하여 회원가입에 성공했습니다.",
content = @Content(schema = @Schema(implementation = MemberNicknameResponseDto.class))
)
@Operation(summary = "유저 닉네임 설정")
public ResponseEntity<ApiResponse<MemberNicknameResponseDto>> setMemberNickname(Principal principal, @Valid @RequestBody MemberNicknameRequestDto request);

@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "마이페이지의 유저 닉네임과 내 레큐북 조회에 성공했습니다.",
content = @Content(schema = @Schema(implementation = MypageBookResponseDto.class))
)
@Operation(summary = "마이페이지 레큐북 조회")
public ResponseEntity<ApiResponse<MypageBookResponseDto>> getMypageBook(Principal principal);

@SecurityRequirement(name = "JWT Authorization")
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "마이페이지의 유저 닉네임과 내 레큐노트 조회에 성공했습니다.",
content = @Content(schema = @Schema(implementation = MypageNoteResponseDto.class))
)
@Operation(summary = "마이페이지 레큐노트 조회")
public ResponseEntity<ApiResponse<MypageNoteResponseDto>> getMypageNote(Principal principal);
}
Loading
Loading