Skip to content

Commit

Permalink
Feat&Refac: 북마크 목록 조회API 구현 및 코드 리팩토링(weekly -> master) Merge
Browse files Browse the repository at this point in the history
Feat&Refac: 북마크 목록 조회API 구현 및 코드 리팩토링(weekly -> master)
  • Loading branch information
Train0303 authored Nov 10, 2023
2 parents be0554a + 55c5dcf commit b3f0ea0
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

import java.util.List;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/bookmark")
Expand All @@ -28,37 +30,37 @@ public class BookmarkController {
public ResponseEntity<?> createBookmark(
@RequestBody @Valid
BookmarkRequestDto.BookmarkAddDto dto,
@AuthenticationPrincipal CustomUserDetails user
@AuthenticationPrincipal CustomUserDetails userDetails
) {
bookmarkService.addBookmark(dto, user.getUser());
bookmarkService.addBookmark(dto, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}

@PostMapping("/delete/{bookmarkId}")
public ResponseEntity<?> deleteBookmark(
@PathVariable Long bookmarkId,
@AuthenticationPrincipal CustomUserDetails user
@AuthenticationPrincipal CustomUserDetails userDetails
) {
bookmarkService.deleteBookmark(bookmarkId, user.getUser());
bookmarkService.deleteBookmark(bookmarkId, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}

@PostMapping("/update/{bookmarkId}")
public ResponseEntity<?> updateBookmark(
@RequestBody @Valid BookmarkRequestDto.BookmarkUpdateRequestDto dto,
@PathVariable Long bookmarkId,
@AuthenticationPrincipal CustomUserDetails user
@AuthenticationPrincipal CustomUserDetails userDetails
) {
BookmarkResponseDto.BookmarkUpdateResponseDto responseDto = bookmarkService.updateBookmark(dto, bookmarkId, user.getUser());
BookmarkResponseDto.BookmarkUpdateResponseDto responseDto = bookmarkService.updateBookmark(dto, bookmarkId, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(responseDto));
}

@PostMapping("/move")
public ResponseEntity<?> moveBookmark(
@RequestBody @Valid BookmarkRequestDto.BookmarkMoveRequestDto dto,
@AuthenticationPrincipal CustomUserDetails user
@AuthenticationPrincipal CustomUserDetails userDetails
) {
bookmarkService.moveBookmark(dto, user.getUser());
bookmarkService.moveBookmark(dto, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}

Expand All @@ -76,10 +78,21 @@ public ResponseEntity<?> getBookmark(
public ResponseEntity<?> searchBookmark(
@RequestBody @Valid BookmarkSearchCondition condition,
@RequestParam(name = "page", defaultValue = "0") int page,
@AuthenticationPrincipal CustomUserDetails user) {
@AuthenticationPrincipal CustomUserDetails userDetails) {
Pageable pageable = PageRequest.of(page, PAGE_SIZE);
BookmarkSearchResponseDto responseDto = bookmarkService.searchBookmark(condition, user.getUser(),
BookmarkSearchResponseDto responseDto = bookmarkService.searchBookmark(condition, userDetails.getUser(),
pageable);
return ResponseEntity.ok(ApiUtils.success(responseDto));
}

// 사용자 계정에 등록된 북마크 목록을 최신순으로 보여준다.
@GetMapping("/list")
public ResponseEntity<?> recentBookmarkList(
@RequestParam(name = "page", defaultValue = "0") int page,
@AuthenticationPrincipal CustomUserDetails userDetails) {
Pageable pageable = PageRequest.of(page, PAGE_SIZE);
List<BookmarkResponseDto.BookmarkGetResponseDto> response =
bookmarkService.getRecentBookmark(pageable, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(response));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.time.LocalDateTime;
import java.util.List;

import com.kakao.linknamu.bookmark.entity.Bookmark;
import com.kakao.linknamu.tag.entity.Tag;

import lombok.Builder;
Expand Down Expand Up @@ -46,6 +47,17 @@ public static BookmarkGetResponseDto of(BookmarkUserQueryDto bookmark, List<Tag>
.createdAt(bookmark.getCreatedAt())
.build();
}
public static BookmarkGetResponseDto of(Bookmark bookmark, List<Tag> tagList) {
return BookmarkGetResponseDto.builder()
.bookmarkId(bookmark.getBookmarkId())
.title(bookmark.getBookmarkName())
.description(bookmark.getBookmarkDescription())
.url(bookmark.getBookmarkLink())
.imageUrl(bookmark.getBookmarkThumbnail())
.tagList(tagList.stream().map(TagDto::of).toList())
.createdAt(bookmark.getCreatedAt())
.build();
}
}

private record TagDto(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.kakao.linknamu.bookmark.entity;

import com.kakao.linknamu.bookmark.BookmarkExceptionStatus;
import com.kakao.linknamu.bookmarktag.entity.BookmarkTag;
import com.kakao.linknamu.category.entity.Category;
import com.kakao.linknamu.core.exception.Exception400;
import com.kakao.linknamu.core.util.AuditingEntity;
Expand All @@ -13,6 +14,7 @@
import org.hibernate.annotations.OnDeleteAction;

import java.util.Objects;
import java.util.Set;

@Getter
@NoArgsConstructor
Expand All @@ -27,7 +29,11 @@
indexes = {
@Index(
name = "bookmark_name_index",
columnList = "bookmark_name")}
columnList = "bookmark_name"),
@Index(
name = "bookmark_created_at_index",
columnList = "createdAt")
}
)
public class Bookmark extends AuditingEntity {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ Optional<Bookmark> findByCategoryIdAndBookmarkLink(@Param("categoryId") Long cat
+ "where b.bookmarkId in :bookmarkIds")
List<Bookmark> searchRequiredBookmarks(@Param("bookmarkIds") List<Long> bookmarkIds);

@Query("select b from Bookmark b "
+ "where b.category.workspace.user.userId = :userId "
+ "order by b.createdAt desc")
Page<Bookmark> recentBookmarks(Pageable pageable, @Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

@Slf4j
@Transactional(readOnly = true)
Expand All @@ -54,6 +54,25 @@ public boolean existByBookmarkLinkAndCategoryId(String bookmarkLink, Long catego
return bookmarkJpaRepository.findByCategoryIdAndBookmarkLink(categoryId, bookmarkLink).isPresent();
}

// 사용자 계정에 등록된 북마크 목록을 최신순으로 보여준다.
public List<BookmarkResponseDto.BookmarkGetResponseDto> getRecentBookmark(Pageable pageable, User user) {
List<Bookmark> bookmarkList = bookmarkJpaRepository.recentBookmarks(pageable, user.getUserId()).toList();
List<BookmarkTag> bookmarkTagList = bookmarkTagJpaRepository.findByBookmarkIdsFetchJoinTag(
bookmarkList
.stream()
.map(Bookmark::getBookmarkId)
.toList()
);

Map<Bookmark, List<Tag>> bookmarkTagListMap = bookmarkTagList.stream()
.collect(groupingBy(BookmarkTag::getBookmark
, Collectors.mapping(BookmarkTag::getTag, toList())));

return bookmarkList.stream()
.map(bookmark -> BookmarkResponseDto.BookmarkGetResponseDto.of(bookmark, bookmarkTagListMap.get(bookmark)))
.toList();
}

@Transactional
public void addBookmark(Bookmark bookmark, Category newCategory, List<Tag> tagList, User user) {
// category는 새로만든 카테고리, 북마크는 과거 북마크 user는 새로운 유저
Expand All @@ -67,7 +86,7 @@ public void addBookmark(Bookmark bookmark, Category newCategory, List<Tag> tagLi

newCategory = categoryService.findByIdFetchJoinWorkspace(newCategory.getCategoryId());

validUser(newCategory, user);
categoryService.validUser(newCategory, user);

bookmarkJpaRepository.save(newBookmark);

Expand All @@ -94,7 +113,7 @@ public void addBookmark(BookmarkRequestDto.BookmarkAddDto bookmarkAddDto, User u
// Bookmark 테이블에 bookmark 항목 추가
Category category = categoryService.findByIdFetchJoinWorkspace(bookmarkAddDto.getCategoryId());

validUser(category, user);
categoryService.validUser(category, user);

// 북마크의 링크에 대한 중복 검사
validDuplicatedLink(category, bookmarkAddDto.getBookmarkLink());
Expand Down Expand Up @@ -148,7 +167,7 @@ public BookmarkResponseDto.BookmarkUpdateResponseDto updateBookmark(
Bookmark bookmark = bookmarkJpaRepository.findByIdFetchJoinCategoryAndWorkspace(bookmarkId)
.orElseThrow(() -> new Exception404(BookmarkExceptionStatus.BOOKMARK_NOT_FOUND));

validUser(bookmark.getCategory(), user);
validUser(bookmark, user);
bookmarkJpaRepository.updateBookmark(bookmarkId, dto.bookmarkName(), dto.description());


Expand All @@ -168,7 +187,7 @@ public BookmarkResponseDto.BookmarkUpdateResponseDto updateBookmark(
public void deleteBookmark(Long bookmarkId, User user) {
Bookmark bookmark = bookmarkJpaRepository.findByIdFetchJoinCategoryAndWorkspace(bookmarkId)
.orElseThrow(() -> new Exception404(BookmarkExceptionStatus.BOOKMARK_NOT_FOUND));
validUser(bookmark.getCategory(), user);
validUser(bookmark, user);
bookmarkJpaRepository.delete(bookmark);
}

Expand All @@ -181,7 +200,7 @@ public void moveBookmark(BookmarkRequestDto.BookmarkMoveRequestDto dto, User use
Set<Long> examineSet = new HashSet<>();

for (Bookmark bookmark : requestedBookmarks) {
validUser(bookmark.getCategory(), user);
validUser(bookmark, user);
// 만약 같은 카테고리로 이동한다면 중복 검사를 할 필요가 없다.
if(!isMoveSameCategory(bookmark.getCategory(), toCategory))
validDuplicatedLink(toCategory, bookmark.getBookmarkLink());
Expand All @@ -205,8 +224,8 @@ public BookmarkSearchResponseDto searchBookmark(BookmarkSearchCondition conditio
return BookmarkSearchResponseDto.of(new PageInfoDto(bookmarks), getBookmarkContentDtos(bookmarks));
}

private void validUser(Category category, User user) {
if (!category.getWorkspace().getUser().getUserId()
public void validUser(Bookmark bookmark, User user) {
if (!bookmark.getCategory().getWorkspace().getUser().getUserId()
.equals(user.getUserId())) {
throw new Exception403(BookmarkExceptionStatus.BOOKMARK_FORBIDDEN);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ public interface BookmarkTagJpaRepository

@Query("select bt from BookmarkTag bt join fetch bt.tag t where bt.bookmarkTagId = :bookmarkTagId")
Optional<BookmarkTag> findByIdFetchJoinTag(@Param("bookmarkTagId") BookmarkTagId bookmarkTagId);

@Query("select bt from BookmarkTag bt join fetch bt.tag t where bt.bookmark.bookmarkId in :bookmarkIdList")
List<BookmarkTag> findByBookmarkIdsFetchJoinTag(@Param("bookmarkIdList") List<Long> BookmarkIdList);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,35 @@ public class CategoryController {
@PostMapping("/create")
public ResponseEntity<?> createCategory(
@RequestBody @Valid CategorySaveRequestDto requestDto,
@AuthenticationPrincipal CustomUserDetails user) {
categoryService.createCategory(requestDto, user.getUser());
@AuthenticationPrincipal CustomUserDetails userDetails) {
categoryService.createCategory(requestDto, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}

@GetMapping("/{categoryId}")
public ResponseEntity<?> getCategory(
@RequestParam(defaultValue = "0") int page,
@PathVariable Long categoryId,
@AuthenticationPrincipal CustomUserDetails user) {
@AuthenticationPrincipal CustomUserDetails userDetails) {
Pageable pageable = PageRequest.of(page, PAGE_SIZE, Sort.by("createdAt").descending());
CategoryGetResponseDto responseDto = categoryService.getCategory(categoryId, user.getUser(), pageable);
CategoryGetResponseDto responseDto = categoryService.getCategory(categoryId, userDetails.getUser(), pageable);
return ResponseEntity.ok(ApiUtils.success(responseDto));
}

@PostMapping("/update/{categoryId}")
public ResponseEntity<?> updateCategory(
@PathVariable Long categoryId,
@RequestBody @Valid CategoryUpdateRequestDto requestDto,
@AuthenticationPrincipal CustomUserDetails user) {
categoryService.update(requestDto, categoryId, user.getUser());
@AuthenticationPrincipal CustomUserDetails userDetails) {
categoryService.update(requestDto, categoryId, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}

@PostMapping("/delete/{categoryId}")
public ResponseEntity<?> deleteCategory(
@PathVariable Long categoryId,
@AuthenticationPrincipal CustomUserDetails user) {
categoryService.delete(categoryId, user.getUser());
@AuthenticationPrincipal CustomUserDetails userDetails) {
categoryService.delete(categoryId, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ public Optional<Category> findByWorkspaceIdAndCategoryName(Long workspaceId, Str
@Transactional
public void createCategory(CategorySaveRequestDto requestDto, User user) {
Workspace workspace = workspaceService.getWorkspaceById(requestDto.workspaceId());
validUser(workspace, user);
workspaceService.validUser(workspace, user);
save(requestDto.categoryName(), workspace);
}

public CategoryGetResponseDto getCategory(Long categoryId, User user, Pageable pageable) {
Category category = findByIdFetchJoinWorkspace(categoryId);
validUser(category.getWorkspace(), user);
validUser(category, user);

Page<Bookmark> bookmarkPage = bookmarkJpaRepository.findByCategoryId(categoryId, pageable);
PageInfoDto pageInfoDto = new PageInfoDto(bookmarkPage);
Expand All @@ -90,21 +90,21 @@ public CategoryGetResponseDto getCategory(Long categoryId, User user, Pageable p
@Transactional
public void update(CategoryUpdateRequestDto requestDto, Long categoryId, User user) {
Category category = findByIdFetchJoinWorkspace(categoryId);
validUser(category.getWorkspace(), user);
validUser(category, user);
validDuplicatedCategoryName(category.getWorkspace().getId(), requestDto.categoryName());
category.updateCategoryName(requestDto.categoryName());
}

@Transactional
public void delete(Long categoryId, User user) {
Category category = findByIdFetchJoinWorkspace(categoryId);
validUser(category.getWorkspace(), user);
validUser(category, user);
categoryJPARepository.deleteById(categoryId);
}


private void validUser(Workspace workspace, User user) {
if (!workspace.getUser().getUserId().equals(user.getUserId())) {
public void validUser(Category category, User user) {
if (!category.getWorkspace().getUser().getUserId().equals(user.getUserId())) {
throw new Exception403(CategoryExceptionStatus.CATEGORY_FORBIDDEN);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ public class ShareController {
// 워크스페이스
@GetMapping("/workspace/{workSpaceId}")
public ResponseEntity<?> createLinkFromWorkSpaceId(
@PathVariable("workSpaceId") @Positive(message = "id는 양수여야한다.") Long workSpaceId) {
String link = shareWorkspaceService.createLink(workSpaceId);
@PathVariable("workSpaceId") @Positive(message = "id는 양수여야한다.") Long workSpaceId,
@AuthenticationPrincipal CustomUserDetails userDetails) {
String link = shareWorkspaceService.createLink(workSpaceId, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(link));
}

Expand All @@ -52,8 +53,9 @@ public ResponseEntity<?> createWorkspaceFromEncodedId(
// 카테고리
@GetMapping("/category/{categoryId}")
public ResponseEntity<?> createLinkFromCategoryId(
@PathVariable("categoryId") @Positive(message = "id는 양수여야한다.") Long categoryId) {
String link = shareCategoryService.createLink(categoryId);
@PathVariable("categoryId") @Positive(message = "id는 양수여야한다.") Long categoryId,
@AuthenticationPrincipal CustomUserDetails userDetails) {
String link = shareCategoryService.createLink(categoryId, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(link));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import com.kakao.linknamu.bookmark.entity.Bookmark;
import com.kakao.linknamu.bookmark.service.BookmarkService;
import com.kakao.linknamu.bookmarktag.service.BookmarkTagService;
import com.kakao.linknamu.category.CategoryExceptionStatus;
import com.kakao.linknamu.category.entity.Category;
import com.kakao.linknamu.category.service.CategoryService;
import com.kakao.linknamu.core.dto.PageInfoDto;
import com.kakao.linknamu.core.encryption.AesEncryption;
import com.kakao.linknamu.core.exception.Exception400;
import com.kakao.linknamu.core.exception.Exception403;
import com.kakao.linknamu.share.dto.category.CreateCategoryFromEncodedIdRequestDto;
import com.kakao.linknamu.share.dto.category.GetCategoryFromLinkResponseDto;
import com.kakao.linknamu.tag.entity.Tag;
Expand Down Expand Up @@ -35,8 +37,9 @@ public class ShareCategoryService {
private final WorkspaceService workspaceService;
private static final String URL = "/share-link/category/share?category=";

public String createLink(Long categoryId) {
categoryService.findById(categoryId);
public String createLink(Long categoryId, User user) {
Category category = categoryService.findByIdFetchJoinWorkspace(categoryId);
categoryService.validUser(category, user);
String encodedString = aesEncryption.encode(categoryId.toString());
return URL + encodedString;
}
Expand Down
Loading

0 comments on commit b3f0ea0

Please sign in to comment.