-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1432 from woowacourse/main
Refactor/1365 커스텀 예외 수정
- Loading branch information
Showing
18 changed files
with
828 additions
and
4 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
backend/src/acceptanceTest/java/wooteco/prolog/fixtures/ArticleFixture.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package wooteco.prolog.fixtures; | ||
|
||
import wooteco.prolog.article.ui.ArticleRequest; | ||
|
||
public class ArticleFixture { | ||
public static final ArticleRequest ARTICLE_REQUEST1 = new ArticleRequest("첫 아티클 제목","첫 아티클 주소"); | ||
public static final ArticleRequest ARTICLE_REQUEST2 = new ArticleRequest("두번째 아티클 제목","두번째 아티클 주소"); | ||
} |
78 changes: 78 additions & 0 deletions
78
backend/src/acceptanceTest/java/wooteco/prolog/steps/ArticleStepDefinitions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package wooteco.prolog.steps; | ||
|
||
import io.cucumber.java.en.Given; | ||
import io.cucumber.java.en.Then; | ||
import io.cucumber.java.en.When; | ||
import org.springframework.http.HttpStatus; | ||
import wooteco.prolog.AcceptanceSteps; | ||
import wooteco.prolog.article.ui.ArticleResponse; | ||
|
||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static wooteco.prolog.fixtures.ArticleFixture.ARTICLE_REQUEST1; | ||
import static wooteco.prolog.fixtures.ArticleFixture.ARTICLE_REQUEST2; | ||
|
||
|
||
public class ArticleStepDefinitions extends AcceptanceSteps { | ||
|
||
@Given("아티클을 여러개 작성하고") | ||
public void 아티클을_여러개_작성하고() { | ||
context.invokeHttpPostWithToken("/articles", ARTICLE_REQUEST1); | ||
context.invokeHttpPostWithToken("/articles", ARTICLE_REQUEST2); | ||
} | ||
|
||
@Given("아티클을 작성하고") | ||
@When("아티클을 작성하면") | ||
public void 아티클을_작성하면() { | ||
context.invokeHttpPostWithToken("/articles", ARTICLE_REQUEST1); | ||
if (context.response.statusCode() == HttpStatus.CREATED.value()) { | ||
context.storage.put("article", context.response.statusCode()); | ||
} | ||
} | ||
|
||
@When("아티클을 전체 조회 하면") | ||
public void 아티클을_전체_조회_하면() { | ||
context.invokeHttpGetWithToken("/articles"); | ||
context.storage.put("articles", context.response.as(Object.class)); | ||
} | ||
|
||
@When("{long}번 아티클을 수정하면") | ||
public void 아티클을_수정하면(Long articleId) { | ||
String path = "/articles/" + articleId; | ||
context.invokeHttpPutWithToken(path, ARTICLE_REQUEST2); | ||
} | ||
|
||
@When("{long}번 아티클을 삭제하면") | ||
public void 아티클을_삭제하면(Long articleId) { | ||
String path = "/articles/" + articleId; | ||
context.invokeHttpDeleteWithToken(path, ARTICLE_REQUEST2); | ||
} | ||
|
||
@Then("아티클이 작성된다") | ||
public void 아티클이_작성된다() { | ||
int statusCode = context.response.statusCode(); | ||
assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value()); | ||
} | ||
|
||
@Then("아티클이 전체 조회 된다") | ||
public void 아티클이_전체_조회된다() { | ||
int statusCode = context.response.statusCode(); | ||
assertThat(statusCode).isEqualTo(HttpStatus.OK.value()); | ||
|
||
List<ArticleResponse> articleResponses = (List<ArticleResponse>) context.storage.get("articles"); | ||
assertThat(articleResponses.size()).isEqualTo(2); | ||
} | ||
|
||
@Then("아티클이 수정된다") | ||
public void 아티클이_수정된다() { | ||
int statusCode = context.response.statusCode(); | ||
assertThat(statusCode).isEqualTo(HttpStatus.OK.value()); | ||
} | ||
|
||
@Then("아티클이 삭제된다") | ||
public void 아티클이_삭제된다() { | ||
int statusCode = context.response.statusCode(); | ||
assertThat(statusCode).isEqualTo(HttpStatus.NO_CONTENT.value()); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
backend/src/acceptanceTest/resources/wooteco/prolog/article.feature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
@api | ||
Feature: 아티클 관련 기능 | ||
|
||
Background: 사전 작업 | ||
Given "브라운"이 로그인을 하고 | ||
|
||
Scenario: 아티클을 작성하기 | ||
When 아티클을 작성하면 | ||
Then 아티클이 작성된다 | ||
|
||
Scenario: 아티클을 전체 조회하기 | ||
Given 아티클을 여러개 작성하고 | ||
When 아티클을 전체 조회 하면 | ||
Then 아티클이 전체 조회 된다 | ||
|
||
Scenario: 아티클을 수정하기 | ||
Given 아티클을 여러개 작성하고 | ||
When 1번 아티클을 수정하면 | ||
Then 아티클이 수정된다 | ||
|
||
Scenario: 아티클을 삭제하기 | ||
Given 아티클을 여러개 작성하고 | ||
When 1번 아티클을 삭제하면 | ||
Then 아티클이 삭제된다 |
61 changes: 61 additions & 0 deletions
61
backend/src/main/java/wooteco/prolog/article/domain/Article.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package wooteco.prolog.article.domain; | ||
|
||
import java.time.LocalDateTime; | ||
import javax.persistence.Embedded; | ||
import javax.persistence.Entity; | ||
import javax.persistence.EntityListeners; | ||
import javax.persistence.FetchType; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.GenerationType; | ||
import javax.persistence.Id; | ||
import javax.persistence.JoinColumn; | ||
import javax.persistence.ManyToOne; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import org.springframework.data.annotation.CreatedDate; | ||
import org.springframework.data.jpa.domain.support.AuditingEntityListener; | ||
import wooteco.prolog.common.exception.BadRequestCode; | ||
import wooteco.prolog.common.exception.BadRequestException; | ||
import wooteco.prolog.member.domain.Member; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@EntityListeners(AuditingEntityListener.class) | ||
public class Article { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "member_id", nullable = false) | ||
private Member member; | ||
|
||
@Embedded | ||
private Title title; | ||
|
||
@Embedded | ||
private Url url; | ||
|
||
@CreatedDate | ||
private LocalDateTime createdAt; | ||
|
||
public Article(final Member member, final Title title, final Url url) { | ||
this.member = member; | ||
this.title = title; | ||
this.url = url; | ||
} | ||
|
||
public void validateOwner(final Member member) { | ||
if (!member.equals(this.member)) { | ||
throw new BadRequestException(BadRequestCode.INVALID_ARTICLE_AUTHOR_EXCEPTION); | ||
} | ||
} | ||
|
||
public void update(final String title, final String url) { | ||
this.title = new Title(title); | ||
this.url = new Url(url); | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
backend/src/main/java/wooteco/prolog/article/domain/ArticleService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package wooteco.prolog.article.domain; | ||
|
||
import static java.util.stream.Collectors.toList; | ||
|
||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import wooteco.prolog.article.domain.repository.ArticleRepository; | ||
import wooteco.prolog.article.ui.ArticleRequest; | ||
import wooteco.prolog.article.ui.ArticleResponse; | ||
import wooteco.prolog.common.exception.BadRequestCode; | ||
import wooteco.prolog.common.exception.BadRequestException; | ||
import wooteco.prolog.login.ui.LoginMember; | ||
import wooteco.prolog.member.application.MemberService; | ||
import wooteco.prolog.member.domain.Member; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
@Transactional(readOnly = true) | ||
public class ArticleService { | ||
|
||
private final ArticleRepository articleRepository; | ||
private final MemberService memberService; | ||
|
||
@Transactional | ||
public Long create(final ArticleRequest articleRequest, final LoginMember loginMember) { | ||
final Member member = memberService.findById(loginMember.getId()); | ||
final Article article = articleRequest.toArticle(member); | ||
return articleRepository.save(article).getId(); | ||
} | ||
|
||
public List<ArticleResponse> getAll() { | ||
return articleRepository.findAll() | ||
.stream() | ||
.map(ArticleResponse::from) | ||
.collect(toList()); | ||
} | ||
|
||
@Transactional | ||
public void update(final Long id, final ArticleRequest articleRequest, | ||
final LoginMember loginMember) { | ||
final Article article = articleRepository.findById(id) | ||
.orElseThrow(() -> new BadRequestException(BadRequestCode.ARTICLE_NOT_FOUND_EXCEPTION)); | ||
|
||
final Member member = memberService.findById(loginMember.getId()); | ||
article.validateOwner(member); | ||
|
||
article.update(articleRequest.getTitle(), articleRequest.getUrl()); | ||
} | ||
|
||
@Transactional | ||
public void delete(final Long id, final LoginMember loginMember) { | ||
final Article article = articleRepository.findById(id) | ||
.orElseThrow(() -> new BadRequestException(BadRequestCode.ARTICLE_NOT_FOUND_EXCEPTION)); | ||
|
||
final Member member = memberService.findById(loginMember.getId()); | ||
article.validateOwner(member); | ||
|
||
articleRepository.delete(article); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
backend/src/main/java/wooteco/prolog/article/domain/Title.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package wooteco.prolog.article.domain; | ||
|
||
import static wooteco.prolog.common.exception.BadRequestCode.ARTICLE_TITLE_NULL_OR_EMPTY_EXCEPTION; | ||
|
||
import java.util.Objects; | ||
import javax.persistence.Column; | ||
import javax.persistence.Embeddable; | ||
import lombok.AccessLevel; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
import wooteco.prolog.common.exception.BadRequestCode; | ||
import wooteco.prolog.common.exception.BadRequestException; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@EqualsAndHashCode | ||
@ToString | ||
@Embeddable | ||
public class Title { | ||
|
||
public static final int MAX_LENGTH = 50; | ||
|
||
@Column(nullable = false, length = MAX_LENGTH) | ||
private String title; | ||
|
||
public Title(String title) { | ||
validateNull(title); | ||
validateEmpty(title); | ||
validateOnlyBlank(title); | ||
validateMaxLength(title); | ||
this.title = trim(title); | ||
} | ||
|
||
private String trim(String name) { | ||
return name.trim(); | ||
} | ||
|
||
private void validateNull(String title) { | ||
if (Objects.isNull(title)) { | ||
throw new BadRequestException(ARTICLE_TITLE_NULL_OR_EMPTY_EXCEPTION); | ||
} | ||
} | ||
|
||
private void validateEmpty(String title) { | ||
if (title.isEmpty()) { | ||
throw new BadRequestException(ARTICLE_TITLE_NULL_OR_EMPTY_EXCEPTION); | ||
} | ||
} | ||
|
||
private void validateOnlyBlank(String title) { | ||
if (title.trim().isEmpty()) { | ||
throw new BadRequestException(ARTICLE_TITLE_NULL_OR_EMPTY_EXCEPTION); | ||
} | ||
} | ||
|
||
private void validateMaxLength(String title) { | ||
if (title.length() > MAX_LENGTH) { | ||
throw new BadRequestException(BadRequestCode.ARTICLE_TITLE_OVER_LENGTH_EXCEPTION); | ||
} | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
backend/src/main/java/wooteco/prolog/article/domain/Url.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package wooteco.prolog.article.domain; | ||
|
||
import static wooteco.prolog.common.exception.BadRequestCode.ARTICLE_URL_OVER_LENGTH_EXCEPTION; | ||
|
||
import java.util.Objects; | ||
import javax.persistence.Column; | ||
import javax.persistence.Embeddable; | ||
import lombok.AccessLevel; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
import wooteco.prolog.common.exception.BadRequestCode; | ||
import wooteco.prolog.common.exception.BadRequestException; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@EqualsAndHashCode | ||
@ToString | ||
@Embeddable | ||
public class Url { | ||
|
||
public static final int MAX_LENGTH = 1024; | ||
|
||
@Column(nullable = false, length = MAX_LENGTH) | ||
private String url; | ||
|
||
public Url(String url) { | ||
validateNull(url); | ||
validateEmpty(url); | ||
validateOnlyBlank(url); | ||
validateMaxLength(url); | ||
this.url = trim(url); | ||
} | ||
|
||
private String trim(String name) { | ||
return name.trim(); | ||
} | ||
|
||
private void validateNull(String url) { | ||
if (Objects.isNull(url)) { | ||
throw new BadRequestException(BadRequestCode.ARTICLE_URL_NULL_OR_EMPTY_EXCEPTION); | ||
} | ||
} | ||
|
||
private void validateEmpty(String url) { | ||
if (url.isEmpty()) { | ||
throw new BadRequestException(BadRequestCode.ARTICLE_URL_NULL_OR_EMPTY_EXCEPTION); | ||
} | ||
} | ||
|
||
private void validateOnlyBlank(String url) { | ||
if (url.trim().isEmpty()) { | ||
throw new BadRequestException(BadRequestCode.ARTICLE_URL_NULL_OR_EMPTY_EXCEPTION); | ||
} | ||
} | ||
|
||
private void validateMaxLength(String url) { | ||
if (url.length() > MAX_LENGTH) { | ||
throw new BadRequestException(ARTICLE_URL_OVER_LENGTH_EXCEPTION); | ||
} | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
backend/src/main/java/wooteco/prolog/article/domain/repository/ArticleRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package wooteco.prolog.article.domain.repository; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import wooteco.prolog.article.domain.Article; | ||
|
||
public interface ArticleRepository extends JpaRepository<Article, Long> { | ||
|
||
} |
Oops, something went wrong.