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] 족보 생성 삭제 API #23

Merged
merged 33 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c5a6503
[feat] add create static method and remove unnecessary filed
PicturePark1101 Jul 6, 2024
e7549bf
[feat] create FavoriteCommandService (before add login logic)
PicturePark1101 Jul 6, 2024
9373042
[feat] create request, command dto
PicturePark1101 Jul 6, 2024
743dd91
[fix] change FavoriteController file name
PicturePark1101 Jul 6, 2024
22bbe3b
[refactor] change dto name
PicturePark1101 Jul 8, 2024
d4ab713
[refactor] change code style
PicturePark1101 Jul 8, 2024
4eaf063
[refactor] change code style
PicturePark1101 Jul 8, 2024
a19a7c8
[refactor] change code style in commandservice
PicturePark1101 Jul 8, 2024
40b0c2d
[refactor] refactor createFavorite return format
PicturePark1101 Jul 8, 2024
371d495
[feat] create findById in FavoriteAdpater
PicturePark1101 Jul 8, 2024
3439ded
[refactor] change package structure
PicturePark1101 Jul 8, 2024
45dbac4
[fix] fix import error occurring after a rebase
PicturePark1101 Jul 8, 2024
6c61d84
[feat] add login
PicturePark1101 Jul 8, 2024
74c14cf
[refactor] reflecting review
PicturePark1101 Jul 8, 2024
ecf2c5a
[feat] implementation multi delete
PicturePark1101 Jul 8, 2024
7b1e057
[refactor] change name finder
PicturePark1101 Jul 8, 2024
200bf00
[feat] add exception
PicturePark1101 Jul 8, 2024
a98f15f
[feat] add batch FavoriteStore
PicturePark1101 Jul 9, 2024
30ea548
[feat] add FavoriteStoreDeleter
PicturePark1101 Jul 9, 2024
766126a
[feat] add Favorite @OneToMany
PicturePark1101 Jul 9, 2024
98460dc
[feat] feat delete FavoriteStore
PicturePark1101 Jul 9, 2024
c9b5c08
[feat] create ErrorCode
PicturePark1101 Jul 9, 2024
147b3cc
[feat] add delete query
PicturePark1101 Jul 9, 2024
af95019
[feat] add Favorite Deleter, Finder and FavoriteStore Deleter
PicturePark1101 Jul 9, 2024
c838a7a
[refactor] refactor response, request dto
PicturePark1101 Jul 9, 2024
9484aac
[feat] add delete and set response
PicturePark1101 Jul 9, 2024
5cb42dc
[feat] add ErrorCode
PicturePark1101 Jul 10, 2024
5b557c4
[refactor] refactor with UnauthorizedException
PicturePark1101 Jul 10, 2024
035ce09
[refactor] Change to in query
PicturePark1101 Jul 11, 2024
702a5f5
[feat] add Column
PicturePark1101 Jul 11, 2024
7ee6a4a
[feat] add image
PicturePark1101 Jul 11, 2024
4200074
[refactor] remove fetch join
PicturePark1101 Jul 11, 2024
1e87ceb
[refactor] apply code review
PicturePark1101 Jul 11, 2024
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
@@ -0,0 +1,38 @@
package org.hankki.hankkiserver.api.favorite.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.hankki.hankkiserver.api.dto.HankkiResponse;
import org.hankki.hankkiserver.api.favorite.controller.request.FavoriteDeleteRequest;
import org.hankki.hankkiserver.api.favorite.service.FavoriteCommandService;
import org.hankki.hankkiserver.api.favorite.service.command.FavoritePostCommand;
import org.hankki.hankkiserver.api.favorite.controller.request.FavoritePostRequest;
import org.hankki.hankkiserver.api.favorite.service.command.FavoritesDeleteCommand;
import org.hankki.hankkiserver.auth.UserId;
import org.hankki.hankkiserver.common.code.CommonSuccessCode;
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.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
public class FavoriteController {

private final FavoriteCommandService favoriteCommandService;

@PostMapping("/favorites")
public HankkiResponse<Void> createFavorite(@UserId final Long userId, @RequestBody @Valid final FavoritePostRequest request) {

favoriteCommandService.create(FavoritePostCommand.of(userId, request));
Comment on lines +25 to +28
Copy link
Contributor

Choose a reason for hiding this comment

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

원래는 201을 내려주면 Location 헤더에 resource의 위치를 포함시켜야 해서
저희 응답을 처리하는 advice에 추후 201상태 코드 가진 친구들에게 location header를 추가해주는 코드를 추가할 예정입니당.
이를 대비해서 create이후에 생성된 리소스의 pk 사용하지 않더라도 일단 갖고 있을 수 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Service return 타입을 Long으로 변경하고
return favoriteRepository.save(Favorite.create(findUser, title, details)).getId();
으로 변경하겠습니다.

return HankkiResponse.success(CommonSuccessCode.CREATED);
}

@PostMapping("/favorites/batch-delete")
public HankkiResponse<Void> deleteFavorite(@UserId final Long userId, @RequestBody final FavoriteDeleteRequest request) {

favoriteCommandService.deleteFavorites(FavoritesDeleteCommand.of(userId, request));
return HankkiResponse.success(CommonSuccessCode.NO_CONTENT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.hankki.hankkiserver.api.favorite.controller.request;

import java.util.List;

public record FavoriteDeleteRequest(
List<Long> favoriteIds
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.hankki.hankkiserver.api.favorite.controller.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.List;

public record FavoritePostRequest(
@NotBlank(message = "제목이 비었습니다.")
@Size(max = 18, message = "제목 길이가 18자를 초과했습니다.")
String title,
@Size(min = 1, max = 2, message = "해시태그 리스트 size가 1 이상 2 이하가 아닙니다.")
List<@Size(min = 2, max= 10, message = "해시태그가 # 포함 10자를 초과했습니다.") String> details
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.hankki.hankkiserver.api.favorite.service;

import jakarta.transaction.Transactional;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.hankki.hankkiserver.api.auth.service.UserFinder;
import org.hankki.hankkiserver.api.favorite.service.command.FavoritesDeleteCommand;
import org.hankki.hankkiserver.api.favoritestore.service.FavoriteStoreDeleter;
import org.hankki.hankkiserver.common.code.UserErrorCode;
import org.hankki.hankkiserver.common.exception.UnauthorizedException;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.hankki.hankkiserver.api.favorite.service.command.FavoritePostCommand;
import org.hankki.hankkiserver.domain.user.model.User;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class FavoriteCommandService {

private final UserFinder userFinder;
private final FavoriteFinder favoriteFinder;
private final FavoriteUpdater favoriteUpdater;
private final FavoriteStoreDeleter favoriteStoreDeleter;
private final FavoriteDeleter favoriteDeleter;

@Transactional
public Long create(final FavoritePostCommand command) {

User findUser = userFinder.getUser(command.userId());
String title = command.title();
String details = String.join(" ", command.details());

return favoriteUpdater.save(Favorite.create(findUser, title, details));
}

@Transactional
public void deleteFavorites(final FavoritesDeleteCommand command) {

List<Favorite> favorites = favoriteFinder.findAllByIds(command.favoriteIds());

favorites.forEach(favorite -> {
if (!favorite.getUser().getId().equals(command.userId())) {
throw new UnauthorizedException(UserErrorCode.USER_FORBIDDEN);
}
});

favoriteStoreDeleter.deleteAllByFavorites(favorites);
favoriteDeleter.deleteAll(favorites);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.hankki.hankkiserver.api.favorite.service;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.hankki.hankkiserver.common.code.BusinessErrorCode;
import org.hankki.hankkiserver.common.exception.InternalServerException;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.hankki.hankkiserver.domain.favorite.repository.FavoriteRepository;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class FavoriteDeleter {

private final FavoriteRepository favoriteRepository;

protected void deleteAll(List<Favorite> favorites) {

Copy link
Contributor

Choose a reason for hiding this comment

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

공백 맞춰주세요

try {
favoriteRepository.deleteAll(favorites);
} catch (Exception e) {
throw new InternalServerException(BusinessErrorCode.INTERNAL_SERVER_ERROR);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.hankki.hankkiserver.api.favorite.service;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.hankki.hankkiserver.common.code.FavoriteErrorCode;
import org.hankki.hankkiserver.common.exception.NotFoundException;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.hankki.hankkiserver.domain.favorite.repository.FavoriteRepository;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class FavoriteFinder {

private final FavoriteRepository favoriteRepository;

public Favorite findById(final Long id) {
return favoriteRepository.findById(id).orElseThrow(() -> new NotFoundException(FavoriteErrorCode.FAVORITE_NOT_FOUND));
}

public List<Favorite> findAllByIds(final List<Long> ids) {
return favoriteRepository.findAllByIds(ids);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.hankki.hankkiserver.api.favorite.service;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.hankki.hankkiserver.common.code.BusinessErrorCode;
import org.hankki.hankkiserver.common.exception.InternalServerException;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.hankki.hankkiserver.domain.favorite.repository.FavoriteRepository;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class FavoriteUpdater {

private final FavoriteRepository favoriteRepository;

protected Long save(Favorite favorite) {
return favoriteRepository.save(favorite).getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.hankki.hankkiserver.api.favorite.service.command;

import java.util.List;
import org.hankki.hankkiserver.api.favorite.controller.request.FavoritePostRequest;

public record FavoritePostCommand(
Long userId,
String title,
List<String> details
) {

public static FavoritePostCommand of(final Long userId, final FavoritePostRequest favoritePostRequest) {

return new FavoritePostCommand(userId, favoritePostRequest.title(), favoritePostRequest.details());

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.hankki.hankkiserver.api.favorite.service.command;

import java.util.List;
import org.hankki.hankkiserver.api.favorite.controller.request.FavoriteDeleteRequest;

public record FavoritesDeleteCommand(
Long userId,
List<Long> favoriteIds
) {

public static FavoritesDeleteCommand of(final Long userId, final FavoriteDeleteRequest favoriteDeleteRequest) {
return new FavoritesDeleteCommand(userId, favoriteDeleteRequest.favoriteIds());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.hankki.hankkiserver.api.favoritestore.service;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.hankki.hankkiserver.common.code.BusinessErrorCode;
import org.hankki.hankkiserver.common.exception.InternalServerException;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.hankki.hankkiserver.domain.favoritestore.repository.FavoriteStoreRepository;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class FavoriteStoreDeleter {

private final FavoriteStoreRepository favoriteStoreRepository;

public void deleteAllByFavorites(List<Favorite> favorites) {

try {
favoriteStoreRepository.deleteAllByFavorites(favorites);
} catch (Exception e) {
throw new InternalServerException(BusinessErrorCode.INTERNAL_SERVER_ERROR);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.hankki.hankkiserver.common.code;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum FavoriteErrorCode implements ErrorCode {

FAVORITE_NOT_FOUND(HttpStatus.NOT_FOUND, "등록되지 않은 족보입니다.");

private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.hankki.hankkiserver.common.code;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum FavoriteStoreErrorCode implements ErrorCode {

FAVORITE_STORE_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 데이터입니다.");

private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
public enum UserErrorCode implements ErrorCode {

USER_NOT_FOUND(HttpStatus.NOT_FOUND, "등록되지 않은 회원입니다."),
USER_INFO_NOT_FOUND(HttpStatus.NOT_FOUND, "회원 정보를 찾을 수 없습니다.");
USER_INFO_NOT_FOUND(HttpStatus.NOT_FOUND, "회원 정보를 찾을 수 없습니다."),
USER_FORBIDDEN(HttpStatus.FORBIDDEN, "리소스에 대한 권한이 없는 회원입니다.");

private final HttpStatus httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package org.hankki.hankkiserver.domain.favorite.model;

import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hankki.hankkiserver.domain.common.BaseTimeEntity;
import org.hankki.hankkiserver.domain.favoritestore.model.FavoriteStore;
import org.hankki.hankkiserver.domain.user.model.User;

@Entity
Expand All @@ -27,6 +31,24 @@ public class Favorite extends BaseTimeEntity {
private String detail;

@Column(nullable = false)
private String favorite_image_url;

private String image_url;

@OneToMany(mappedBy = "favorite")
private List<FavoriteStore> favoriteStores = new ArrayList<>();

public static Favorite create(User user, String name, String detail) {
return Favorite.builder()
.user(user)
.name(name)
.detail(detail)
.build();
}

@Builder
Copy link
Member

Choose a reason for hiding this comment

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

클래스 레벨에 @builder 작성해주면 해당 내용 없이도 builder 사용하실 수 있어요!

Copy link
Contributor

Choose a reason for hiding this comment

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

저는 개인적으로 사용하는 필드들만 갖는 생성자 만든 후에 그 위에 @builder 붙이는 거 선호합니다.

private Favorite(User user, String name, String detail) {
this.user = user;
this.name = name;
this.detail = detail;
this.image_url = "default.com";
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
package org.hankki.hankkiserver.domain.favorite.repository;

import java.util.List;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface FavoriteRepository extends JpaRepository<Favorite, Long> {

@Modifying
@Query("delete from Favorite f where f in :favorites")
void deleteAll(@Param("favorites") List<Favorite> favorites);

@Query("select f from Favorite f where f.id in :favoriteId")
List<Favorite> findAllByIds(@Param("favoriteId") List<Long> favoriteId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import lombok.NoArgsConstructor;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.hankki.hankkiserver.domain.store.model.Store;
import org.hibernate.annotations.BatchSize;

@Entity
@Getter
@BatchSize(size = 100)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FavoriteStore {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package org.hankki.hankkiserver.domain.favoritestore.repository;

import java.util.List;
import org.hankki.hankkiserver.domain.favorite.model.Favorite;
import org.hankki.hankkiserver.domain.favoritestore.model.FavoriteStore;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface FavoriteStoreRepository extends JpaRepository<FavoriteStore, Long> {

@Modifying
@Query("delete from FavoriteStore fs where fs.favorite in :favorites")
void deleteAllByFavorites(@Param("favorites")List<Favorite> favorites);
}
Loading