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

Feat&Refac: 북마크 목록 조회API 구현 및 코드 리팩토링(weekly -> master) #227

Merged
merged 5 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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