-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #76 from jisung-in/feature/73-user-library-crud-api
[Feature] UserLibrary CRUD 기능 구현
- Loading branch information
Showing
17 changed files
with
1,057 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
src/main/java/com/jisungin/api/userlibrary/UserLibraryController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.jisungin.api.userlibrary; | ||
|
||
import com.jisungin.api.ApiResponse; | ||
import com.jisungin.api.oauth.Auth; | ||
import com.jisungin.api.userlibrary.request.UserLibraryCreateRequest; | ||
import com.jisungin.api.userlibrary.request.UserLibraryEditRequest; | ||
import com.jisungin.application.userlibrary.UserLibraryService; | ||
import com.jisungin.application.userlibrary.response.UserLibraryResponse; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PatchMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/v1") | ||
public class UserLibraryController { | ||
|
||
private final UserLibraryService userLibraryService; | ||
|
||
@GetMapping("/user-libraries") | ||
public ApiResponse<UserLibraryResponse> getUserLibrary(@RequestParam String isbn, | ||
@Auth Long userId | ||
) { | ||
return ApiResponse.ok(userLibraryService.getUserLibrary(userId, isbn)); | ||
} | ||
|
||
@PostMapping("/user-libraries") | ||
public ApiResponse<UserLibraryResponse> createUserLibrary(@Valid @RequestBody UserLibraryCreateRequest request, | ||
@Auth Long userId | ||
) { | ||
return ApiResponse.ok(userLibraryService.createUserLibrary(request.toServiceRequest(), userId)); | ||
} | ||
|
||
@PatchMapping("/user-libraries/{userLibraryId}") | ||
public ApiResponse<Void> editUserLibrary(@PathVariable("userLibraryId") Long userLibraryId, | ||
@Valid @RequestBody UserLibraryEditRequest request, | ||
@Auth Long userId | ||
) { | ||
userLibraryService.editUserLibrary(userLibraryId, userId, request.toServiceRequest()); | ||
|
||
return ApiResponse.ok(); | ||
} | ||
|
||
@DeleteMapping("/user-libraries/{userLibraryId}") | ||
public ApiResponse<Void> deleteUserLibrary(@PathVariable("userLibraryId") Long userLibraryId, | ||
@RequestParam String isbn, | ||
@Auth Long userId | ||
) { | ||
userLibraryService.deleteUserLibrary(userLibraryId, userId, isbn); | ||
|
||
return ApiResponse.ok(); | ||
} | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/com/jisungin/api/userlibrary/request/UserLibraryCreateRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.jisungin.api.userlibrary.request; | ||
|
||
import com.jisungin.application.userlibrary.request.UserLibraryCreateServiceRequest; | ||
import jakarta.validation.constraints.NotBlank; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class UserLibraryCreateRequest { | ||
|
||
@NotBlank(message = "책 isbn 입력은 필수 입니다.") | ||
private String isbn; | ||
|
||
@NotBlank(message = "독서 상태 정보 입력은 필수 입니다.") | ||
private String readingStatus; | ||
|
||
@Builder | ||
private UserLibraryCreateRequest(String isbn, String readingStatus) { | ||
this.isbn = isbn; | ||
this.readingStatus = readingStatus; | ||
} | ||
|
||
public UserLibraryCreateServiceRequest toServiceRequest() { | ||
return UserLibraryCreateServiceRequest.builder() | ||
.isbn(isbn) | ||
.readingStatus(readingStatus) | ||
.build(); | ||
} | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/com/jisungin/api/userlibrary/request/UserLibraryEditRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.jisungin.api.userlibrary.request; | ||
|
||
import com.jisungin.application.userlibrary.request.UserLibraryEditServiceRequest; | ||
import jakarta.validation.constraints.NotBlank; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class UserLibraryEditRequest { | ||
|
||
@NotBlank(message = "책 isbn 입력은 필수 입니다.") | ||
private String isbn; | ||
|
||
@NotBlank(message = "독서 상태 정보 입력은 필수 입니다.") | ||
private String readingStatus; | ||
|
||
@Builder | ||
private UserLibraryEditRequest(String isbn, String readingStatus) { | ||
this.isbn = isbn; | ||
this.readingStatus = readingStatus; | ||
} | ||
|
||
public UserLibraryEditServiceRequest toServiceRequest() { | ||
return UserLibraryEditServiceRequest.builder() | ||
.isbn(isbn) | ||
.readingStatus(readingStatus) | ||
.build(); | ||
} | ||
|
||
} |
103 changes: 103 additions & 0 deletions
103
src/main/java/com/jisungin/application/userlibrary/UserLibraryService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package com.jisungin.application.userlibrary; | ||
|
||
import com.jisungin.application.userlibrary.request.UserLibraryCreateServiceRequest; | ||
import com.jisungin.application.userlibrary.request.UserLibraryEditServiceRequest; | ||
import com.jisungin.application.userlibrary.response.UserLibraryResponse; | ||
import com.jisungin.domain.ReadingStatus; | ||
import com.jisungin.domain.book.Book; | ||
import com.jisungin.domain.book.repository.BookRepository; | ||
import com.jisungin.domain.mylibrary.UserLibrary; | ||
import com.jisungin.domain.mylibrary.repository.UserLibraryRepository; | ||
import com.jisungin.domain.user.User; | ||
import com.jisungin.domain.user.repository.UserRepository; | ||
import com.jisungin.exception.BusinessException; | ||
import com.jisungin.exception.ErrorCode; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
public class UserLibraryService { | ||
|
||
private final UserRepository userRepository; | ||
private final BookRepository bookRepository; | ||
private final UserLibraryRepository userLibraryRepository; | ||
|
||
public UserLibraryResponse getUserLibrary(Long userId, String isbn) { | ||
if (userId == null || isbn == null) { | ||
return UserLibraryResponse.empty(); | ||
} | ||
|
||
User user = userRepository.findById(userId) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); | ||
|
||
Book book = bookRepository.findById(isbn) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); | ||
|
||
UserLibrary userLibrary = userLibraryRepository.findByUserAndBook(user, book); | ||
|
||
return UserLibraryResponse.of(userLibrary); | ||
} | ||
|
||
@Transactional | ||
public UserLibraryResponse createUserLibrary(UserLibraryCreateServiceRequest request, Long userId) { | ||
User user = userRepository.findById(userId) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); | ||
|
||
Book book = bookRepository.findById(request.getIsbn()) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); | ||
|
||
UserLibrary savedUserLibrary = userLibraryRepository.save(request.toEntity(user, book)); | ||
|
||
return UserLibraryResponse.of(savedUserLibrary); | ||
} | ||
|
||
@Transactional | ||
public void editUserLibrary(Long userLibraryId, Long userId, UserLibraryEditServiceRequest request) { | ||
User user = userRepository.findById(userId) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); | ||
|
||
Book book = bookRepository.findById(request.getIsbn()) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); | ||
|
||
UserLibrary userLibrary = userLibraryRepository.findByIdWithBookAndUser(userLibraryId) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_LIBRARY_NOT_FOUND)); | ||
|
||
if (!userLibrary.isUserLibraryOwner(user.getId())) { | ||
throw new BusinessException(ErrorCode.UNAUTHORIZED_REQUEST); | ||
} | ||
|
||
if (!userLibrary.isSameBook(book.getIsbn())) { | ||
throw new BusinessException(ErrorCode.BOOK_INVALID_INFO); | ||
} | ||
|
||
userLibrary.editReadingStatus(ReadingStatus.createReadingStatus(request.getReadingStatus())); | ||
} | ||
|
||
@Transactional | ||
public void deleteUserLibrary(Long userLibraryId, Long userId, String isbn) { | ||
User user = userRepository.findById(userId) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); | ||
|
||
Book book = bookRepository.findById(isbn) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); | ||
|
||
UserLibrary userLibrary = userLibraryRepository.findByIdWithBookAndUser(userLibraryId) | ||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_LIBRARY_NOT_FOUND)); | ||
|
||
if (!userLibrary.isUserLibraryOwner(user.getId())) { | ||
throw new BusinessException(ErrorCode.UNAUTHORIZED_REQUEST); | ||
} | ||
|
||
if (!userLibrary.isSameBook(book.getIsbn())) { | ||
throw new BusinessException(ErrorCode.BOOK_INVALID_INFO); | ||
} | ||
|
||
userLibraryRepository.deleteById(userLibrary.getId()); | ||
} | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
...in/java/com/jisungin/application/userlibrary/request/UserLibraryCreateServiceRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.jisungin.application.userlibrary.request; | ||
|
||
import com.jisungin.domain.ReadingStatus; | ||
import com.jisungin.domain.book.Book; | ||
import com.jisungin.domain.mylibrary.UserLibrary; | ||
import com.jisungin.domain.user.User; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class UserLibraryCreateServiceRequest { | ||
|
||
private String isbn; | ||
private String readingStatus; | ||
|
||
@Builder | ||
private UserLibraryCreateServiceRequest(String isbn, String readingStatus) { | ||
this.isbn = isbn; | ||
this.readingStatus = readingStatus; | ||
} | ||
|
||
public UserLibrary toEntity(User user, Book book) { | ||
return UserLibrary.builder() | ||
.user(user) | ||
.book(book) | ||
.status(ReadingStatus.createReadingStatus(readingStatus)) | ||
.build(); | ||
} | ||
|
||
} |
21 changes: 21 additions & 0 deletions
21
...main/java/com/jisungin/application/userlibrary/request/UserLibraryEditServiceRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.jisungin.application.userlibrary.request; | ||
|
||
import com.jisungin.api.userlibrary.request.UserLibraryCreateRequest; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class UserLibraryEditServiceRequest { | ||
|
||
private String isbn; | ||
private String readingStatus; | ||
|
||
@Builder | ||
private UserLibraryEditServiceRequest(String isbn, String readingStatus) { | ||
this.isbn = isbn; | ||
this.readingStatus = readingStatus; | ||
} | ||
|
||
} |
42 changes: 42 additions & 0 deletions
42
src/main/java/com/jisungin/application/userlibrary/response/UserLibraryResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.jisungin.application.userlibrary.response; | ||
|
||
|
||
import com.jisungin.domain.mylibrary.UserLibrary; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class UserLibraryResponse { | ||
|
||
private Long id; | ||
private String status; | ||
private Boolean hasReadingStatus; | ||
|
||
@Builder | ||
private UserLibraryResponse(Long id, String status, Boolean hasReadingStatus) { | ||
this.id = id; | ||
this.status = status; | ||
this.hasReadingStatus = hasReadingStatus; | ||
} | ||
|
||
public static UserLibraryResponse of(UserLibrary userLibrary) { | ||
if (userLibrary == null) { | ||
return empty(); | ||
} | ||
|
||
return UserLibraryResponse.builder() | ||
.id(userLibrary.getId()) | ||
.status(userLibrary.getStatus().getText()) | ||
.hasReadingStatus(true) | ||
.build(); | ||
} | ||
|
||
public static UserLibraryResponse empty() { | ||
return UserLibraryResponse.builder() | ||
.hasReadingStatus(false) | ||
.build(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.