Skip to content

Commit

Permalink
[feat] 족보 생성 삭제 API (#23)
Browse files Browse the repository at this point in the history
* [feat] add create static method and remove unnecessary filed

* [feat] create FavoriteCommandService (before add login logic)

* [feat] create request, command dto

* [fix] change FavoriteController file name

* [refactor] change dto name

* [refactor] change code style

* [refactor] change code style

* [refactor] change code style in commandservice

* [refactor] refactor createFavorite return format

* [feat] create findById in FavoriteAdpater

* [refactor] change package structure

* [fix] fix import error occurring after a rebase

* [feat] add login

* [refactor] reflecting review

* [feat] implementation multi delete

* [refactor] change name finder

* [feat] add exception

* [feat] add batch FavoriteStore

* [feat] add FavoriteStoreDeleter

* [feat] add Favorite @onetomany

* [feat] feat delete FavoriteStore

* [feat] create ErrorCode

* [feat] add delete query

* [feat] add Favorite Deleter, Finder and FavoriteStore Deleter

* [refactor] refactor response, request dto

* [feat] add delete and set response

* [feat] add ErrorCode

* [refactor] refactor with UnauthorizedException

* [refactor] Change to in query

* [feat] add Column

* [feat] add image

* [refactor] remove fetch join

* [refactor] apply code review
  • Loading branch information
PicturePark1101 authored Jul 11, 2024
1 parent f67d575 commit 71d52d2
Show file tree
Hide file tree
Showing 17 changed files with 313 additions and 3 deletions.
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));
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) {

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
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);
}

0 comments on commit 71d52d2

Please sign in to comment.