Skip to content

Commit

Permalink
Merge pull request #1432 from woowacourse/main
Browse files Browse the repository at this point in the history
Refactor/1365 커스텀 예외 수정
  • Loading branch information
This2sho authored Jul 19, 2023
2 parents 7b58149 + f03c1a4 commit f3ea20a
Show file tree
Hide file tree
Showing 18 changed files with 828 additions and 4 deletions.
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("두번째 아티클 제목","두번째 아티클 주소");
}
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());
}
}
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 backend/src/main/java/wooteco/prolog/article/domain/Article.java
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);
}
}
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 backend/src/main/java/wooteco/prolog/article/domain/Title.java
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 backend/src/main/java/wooteco/prolog/article/domain/Url.java
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);
}
}
}
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> {

}
Loading

0 comments on commit f3ea20a

Please sign in to comment.