Skip to content

Commit 4191f24

Browse files
committed
feat : 북마크 생성 api 추가(#116)
1 parent 5cc0bcc commit 4191f24

File tree

17 files changed

+460
-5
lines changed

17 files changed

+460
-5
lines changed

src/docs/asciidoc/user-api.adoc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,27 @@ include::{snippetsDir}/userExit/1/http-response.adoc[]
176176

177177
==== Response Body Fields
178178
include::{snippetsDir}/userExit/1/response-fields.adoc[]
179+
180+
=== **10. 북마크 생성 api**
181+
182+
게시글 북마크를 생성
183+
184+
==== Request
185+
include::{snippetsDir}/createBookmark/1/http-request.adoc[]
186+
187+
==== Request Body Fields
188+
include::{snippetsDir}/createBookmark/1/request-fields.adoc[]
189+
190+
==== 성공 Response
191+
성공 1. 북마크가 새롭게 생성된 경우 : CREATED
192+
include::{snippetsDir}/createBookmark/1/http-response.adoc[]
193+
194+
성공 2. 이미 존재하는 북마크에 대해 생성 요청을 보낸 경우 : OK
195+
include::{snippetsDir}/createBookmark/2/http-response.adoc[]
196+
197+
==== Response Body Fields
198+
include::{snippetsDir}/createBookmark/1/response-fields.adoc[]
199+
200+
==== 실패 Response
201+
실패1.
202+
include::{snippetsDir}/createBookmark/3/http-response.adoc[]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.ftm.server.adapter.in.web.user.controller;
2+
3+
import com.ftm.server.adapter.in.web.user.dto.request.CreateBookmarkRequest;
4+
import com.ftm.server.application.command.user.CreateBookmarkCommand;
5+
import com.ftm.server.application.port.in.user.CreateBookmarkUseCase;
6+
import com.ftm.server.common.response.ApiResponse;
7+
import com.ftm.server.common.response.enums.SuccessResponseCode;
8+
import com.ftm.server.infrastructure.security.UserPrincipal;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.http.HttpStatus;
11+
import org.springframework.http.ResponseEntity;
12+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
13+
import org.springframework.web.bind.annotation.PostMapping;
14+
import org.springframework.web.bind.annotation.RequestBody;
15+
import org.springframework.web.bind.annotation.RestController;
16+
17+
@RestController
18+
@RequiredArgsConstructor
19+
public class CreateBookmarkController {
20+
21+
private final CreateBookmarkUseCase createBookmarkUseCase;
22+
23+
@PostMapping("/api/users/bookmarks")
24+
public ResponseEntity<ApiResponse> createBookMark(
25+
@AuthenticationPrincipal UserPrincipal user,
26+
@RequestBody CreateBookmarkRequest request) {
27+
Boolean isCreated =
28+
createBookmarkUseCase.execute(
29+
CreateBookmarkCommand.of(user.getId(), request.getPostId()));
30+
HttpStatus httpStatus = isCreated ? HttpStatus.CREATED : HttpStatus.OK;
31+
SuccessResponseCode successResponseCode =
32+
isCreated ? SuccessResponseCode.CREATED : SuccessResponseCode.OK;
33+
return ResponseEntity.status(httpStatus).body(ApiResponse.success(successResponseCode));
34+
}
35+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.ftm.server.adapter.in.web.user.dto.request;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class CreateBookmarkRequest {
7+
private final Long postId;
8+
}

src/main/java/com/ftm/server/adapter/out/persistence/adapter/user/UserDomainPersistenceAdapter.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.ftm.server.adapter.out.persistence.adapter.user;
22

3-
import com.ftm.server.adapter.out.persistence.mapper.EmailVerificationLogsMapper;
4-
import com.ftm.server.adapter.out.persistence.mapper.PostMapper;
5-
import com.ftm.server.adapter.out.persistence.mapper.UserImageMapper;
6-
import com.ftm.server.adapter.out.persistence.mapper.UserMapper;
3+
import com.ftm.server.adapter.out.persistence.mapper.*;
74
import com.ftm.server.adapter.out.persistence.model.*;
85
import com.ftm.server.adapter.out.persistence.repository.*;
96
import com.ftm.server.application.command.user.*;
@@ -18,6 +15,7 @@
1815
import java.util.Optional;
1916
import lombok.RequiredArgsConstructor;
2017
import lombok.extern.slf4j.Slf4j;
18+
import org.springframework.dao.DataIntegrityViolationException;
2119

2220
@Adapter
2321
@RequiredArgsConstructor
@@ -38,7 +36,10 @@ public class UserDomainPersistenceAdapter
3836
DeleteUserImagePort,
3937
DeleteGroomingTestResultPort,
4038
DeleteUserPort,
41-
DeleteBookmarkPort {
39+
DeleteBookmarkPort,
40+
SaveBookmarkPort,
41+
CheckBookmarkPort,
42+
CheckPostPort {
4243

4344
// repository
4445
private final EmailVerificationLogsRepository emailVerificationLogsRepository;
@@ -54,6 +55,7 @@ public class UserDomainPersistenceAdapter
5455
private final UserMapper userMapper;
5556
private final UserImageMapper userImageMapper;
5657
private final PostMapper postMapper;
58+
private final BookmarkMapper bookmarkMapper;
5759

5860
@Override
5961
public Optional<EmailVerificationLogs> loadEmailVerificationLogByEmail(FindByEmailQuery query) {
@@ -110,6 +112,11 @@ public Boolean checksUserBySocialValue(FindBySocialValueQuery query) {
110112
query.getSocialId(), query.getSocialProvider());
111113
}
112114

115+
@Override
116+
public Boolean checksUserById(FindByUserIdQuery query) {
117+
return userRepository.existsById(query.getUserId());
118+
}
119+
113120
@Override
114121
public User saveSocialUser(User user) {
115122
UserJpaEntity userJpaEntity = userMapper.toJpaEntity(user, null);
@@ -223,4 +230,30 @@ public void deleteAllUserByIdList(DeleteAllUserByIdListCommand command) {
223230
public void deleteBookmarkByUserList(DeleteBookmarkByUserIdCommand command) {
224231
bookmarkRepository.deleteAllByUserIdList(command.getUserIdList());
225232
}
233+
234+
@Override
235+
public Boolean saveBookmark(Bookmark bookmark) {
236+
// 이미 생성된 북마크인 경우 -> false
237+
// 새롭게 생성된 북마크인 경우 -> true
238+
int isCreated;
239+
try {
240+
isCreated = bookmarkRepository.saveOrUpdate(bookmark.getUserId(), bookmark.getPostId());
241+
} catch (
242+
DataIntegrityViolationException
243+
e) { // on conflict로 문제 예방 했지만, 동시성 문제로 unique key 위반 에러 나는 경우, 에러 반환하지 않고
244+
// 그냥 처리(북마크 생성하지 않고 OK 반환)
245+
return false;
246+
}
247+
return isCreated == 1;
248+
}
249+
250+
@Override
251+
public Boolean checkIfBookmarkExists(FindBookmarkByUserIdAndPostIdQuery query) {
252+
return bookmarkRepository.existsByUserIdAndPostId(query.getUserId(), query.getPostId());
253+
}
254+
255+
@Override
256+
public Boolean checksPostById(FindByPostIdQuery query) {
257+
return postRepository.existsById(query.getPostId());
258+
}
226259
}

src/main/java/com/ftm/server/adapter/out/persistence/repository/BookmarkRepository.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,16 @@ public interface BookmarkRepository extends JpaRepository<BookmarkJpaEntity, Lon
1111
@Modifying
1212
@Query("DELETE FROM BookmarkJpaEntity b WHERE b.user.id in (:userIds)")
1313
void deleteAllByUserIdList(@Param("userIds") List<Long> userIds);
14+
15+
@Modifying
16+
@Query(
17+
value =
18+
"INSERT INTO bookmark (user_id, post_id) "
19+
+ "VALUES (:userId, :postId) "
20+
+ "ON CONFLICT (user_id, post_id) "
21+
+ "DO NOTHING;",
22+
nativeQuery = true)
23+
int saveOrUpdate(@Param("userId") Long userId, @Param("postId") Long postId);
24+
25+
Boolean existsByUserIdAndPostId(Long userId, Long postId);
1426
}

src/main/java/com/ftm/server/adapter/out/persistence/repository/PostRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ public interface PostRepository extends JpaRepository<PostJpaEntity, Long>, Post
1414
@Modifying
1515
@Query("DELETE FROM PostJpaEntity p WHERE p.id IN (:postIds)")
1616
void deleteAllByIdInBatch(@Param("postIds") List<Long> postIds);
17+
18+
boolean existsById(Long id);
1719
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.ftm.server.application.command.user;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class CreateBookmarkCommand {
7+
private final Long userId;
8+
private final Long postId;
9+
10+
public static CreateBookmarkCommand of(Long userId, Long postId) {
11+
return new CreateBookmarkCommand(userId, postId);
12+
}
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.ftm.server.application.port.in.user;
2+
3+
import com.ftm.server.application.command.user.CreateBookmarkCommand;
4+
import com.ftm.server.common.annotation.UseCase;
5+
6+
@UseCase
7+
public interface CreateBookmarkUseCase {
8+
Boolean execute(CreateBookmarkCommand command);
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.ftm.server.application.port.out.persistence.user;
2+
3+
import com.ftm.server.application.query.FindBookmarkByUserIdAndPostIdQuery;
4+
import com.ftm.server.common.annotation.Port;
5+
6+
@Port
7+
public interface CheckBookmarkPort {
8+
9+
Boolean checkIfBookmarkExists(FindBookmarkByUserIdAndPostIdQuery query);
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.ftm.server.application.port.out.persistence.user;
2+
3+
import com.ftm.server.application.query.FindByPostIdQuery;
4+
5+
public interface CheckPostPort {
6+
Boolean checksPostById(FindByPostIdQuery query);
7+
}

0 commit comments

Comments
 (0)