diff --git a/.github/workflows/autoTest.yml b/.github/workflows/autoTest.yml
index 284811d..8e1a4e2 100644
--- a/.github/workflows/autoTest.yml
+++ b/.github/workflows/autoTest.yml
@@ -33,4 +33,52 @@ jobs:
if: always()
with:
junit_files: "build/test-results/test/**/*.xml"
-
+
+ # 전송할 파일을 담을 디렉토리 생성
+ - name: Make Directory for deliver
+ run: mkdir deploy
+
+ # Jar 파일 Copy
+ - name: Copy Jar
+ run: cp ./build/libs/*.jar ./deploy/
+
+ # appspec.yml 파일 복사
+ - name: Copy appspec.yml
+ run: cp appspec.yml ./deploy
+
+ # deploy.sh 파일 복사
+ - name: Copy deploy.sh
+ run: cp deploy.sh ./deploy
+
+ # test 파일 넘기기
+ - name: Copy doc
+ run: cp -r doc/ ./deploy
+ working-directory: ${{env.working-directory}}
+
+ # 압축파일 형태로 전달
+ - name: Make zip file
+ run: zip -r -qq -j ./realworld.zip ./deploy
+ working-directory: ${{env.working-directory}}
+
+ # S3 Bucket으로 copy
+ - name: Deliver to AWS S3
+ env:
+ AWS_S3_BUCKET: ${{secrets.AWS_PRODUCTION_BUCKET_NAME}}
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_IAM_MANAGER_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_IAM_MANAGER_SECRET_ACCESS_KEY }}
+ AWS_REGION: ap-northeast-2
+ run: |
+ aws s3 cp --region ap-northeast-2 --acl private ./realworld.zip s3://$AWS_S3_BUCKET
+
+ # 배포
+ - name: CodeDeploy
+ env:
+ AWS_S3_BUCKET: ${{secrets.AWS_PRODUCTION_BUCKET_NAME}}
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_IAM_MANAGER_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_IAM_MANAGER_SECRET_ACCESS_KEY }}
+ run: |
+ aws deploy create-deployment \
+ --application-name real-world \
+ --deployment-group-name real-world-group \
+ --s3-location bucket=$AWS_S3_BUCKET,key=realworld.zip,bundleType=zip \
+ --region ap-northeast-2
diff --git a/README.md b/README.md
index 2faf772..7c907c4 100644
--- a/README.md
+++ b/README.md
@@ -10,3 +10,16 @@ This codebase was created to demonstrate a fully fledged fullstack application b
We've gone to great lengths to adhere to the **[Spring Boot]** community styleguides & best practices.
For more information on how to this works with other frontends/backends, head over to the [RealWorld](https://github.com/gothinkster/realworld) repo.
+
+## Enter
+
+```text
+ //temp
+```
+
+## BackEnd - Spring
+
+### Test Scripts
+
+
+
diff --git a/appspec.yml b/appspec.yml
new file mode 100644
index 0000000..afa6df6
--- /dev/null
+++ b/appspec.yml
@@ -0,0 +1,18 @@
+version: 0.0
+os: linux
+files:
+ - source: /
+ destination: /home/linux/app
+ overwrite: yes
+
+permissions:
+ - object: /
+ pattern: "**"
+ owner: ec2-user
+ group: ec2-user
+
+hooks:
+ ApplicationStart:
+ - location: deploy.sh
+ timeout: 60
+ runas: ec2-user
diff --git a/deploy.sh b/deploy.sh
new file mode 100644
index 0000000..5943e50
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+REPOSITORY=/home/ubuntu/app
+
+echo "> 현재 구동 중인 애플리케이션 pid 확인"
+
+CURRENT_PID=$(pgrep -fl action | grep java | awk '{print $1}')
+
+echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID"
+
+if [ -z "$CURRENT_PID" ]; then
+ echo "현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
+else
+ echo "> kill -15 $CURRENT_PID"
+ kill -15 $CURRENT_PID
+ sleep 5
+fi
+
+echo "> 새 애플리케이션 배포"
+
+JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1)
+
+echo "> JAR NAME: $JAR_NAME"
+
+echo "> $JAR_NAME 에 실행권한 추가"
+
+chmod +x $JAR_NAME
+
+echo "> $JAR_NAME 실행"
+
+nohup java -jar $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
\ No newline at end of file
diff --git a/src/main/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImpl.java b/src/main/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImpl.java
index 59596e1..62dc028 100644
--- a/src/main/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImpl.java
+++ b/src/main/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImpl.java
@@ -52,13 +52,9 @@ public class ArticleServiceImpl implements ArticleService {
if (articleParam.getTag() != null) {
articles = articleRepository.findByTag(articleParam.getTag(), pageable);
- }
-
- if(articleParam.getAuthor() != null){
+ }else if(articleParam.getAuthor() != null){
articles = articleRepository.findByAuthorName(articleParam.getAuthor(), pageable);
- }
-
- if(articleParam.getFavorited() != null){
+ }else if(articleParam.getFavorited() != null){
articles = articleRepository.findByFavoritedUser(articleParam.getFavorited(), pageable);
}
@@ -76,10 +72,14 @@ public class ArticleServiceImpl implements ArticleService {
Pageable pageable = PageRequest.of(offset,limit);
List follows = profileRepository.findByFollowerId(userAuth.getId());
- System.out.println(follows.size());
- follows.stream().forEach(follow -> System.out.println(follow.getFollower().getUsername()));
+ follows.stream().forEach(follow -> {
+ String followerName = follow.getFollower().getUsername();
+ articles.addAll(articleRepository.findByAuthorName(followerName,pageable));
+ });
- return List.of();
+ return articles.stream().map(article -> {
+ return convertDtoWithUser(article,userAuth);
+ }).collect(Collectors.toList());
}
// token을 받을수도 안 받을수도 있음.
diff --git a/src/test/java/com/io/realworld/domain/aggregate/article/controller/ArticleControllerTest.java b/src/test/java/com/io/realworld/domain/aggregate/article/controller/ArticleControllerTest.java
index 02a2e94..06b31ef 100644
--- a/src/test/java/com/io/realworld/domain/aggregate/article/controller/ArticleControllerTest.java
+++ b/src/test/java/com/io/realworld/domain/aggregate/article/controller/ArticleControllerTest.java
@@ -5,18 +5,12 @@ import com.io.realworld.config.WithAuthUser;
import com.io.realworld.domain.aggregate.article.dto.*;
import com.io.realworld.domain.aggregate.article.service.ArticleService;
import com.io.realworld.domain.aggregate.article.service.CommentService;
-import com.io.realworld.domain.aggregate.profile.dto.ProfileResponse;
import com.io.realworld.domain.aggregate.user.dto.UserAuth;
-import com.io.realworld.domain.aggregate.user.dto.UserUpdate;
import com.io.realworld.domain.service.JwtService;
-import lombok.With;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
@@ -28,7 +22,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
-import java.util.stream.Stream;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -70,6 +63,7 @@ class ArticleControllerTest {
slug = title.toLowerCase().replace(' ','-');
articleResponse = ArticleResponse.builder()
.author(ArticleResponse.Author.builder().bio("bio")
+ .username("kms")
.following(false)
.username("madeArticle")
.image("image")
@@ -89,6 +83,40 @@ class ArticleControllerTest {
.build();
}
+ @WithAuthUser
+ @Test
+ @DisplayName("게시글들 가져오기 컨트롤러 테스트")
+ void getArticles() throws Exception{
+ List articleResponses = List.of(articleResponse);
+ when(articleService.getArticles(any(UserAuth.class), any(ArticleParam.class))).thenReturn(articleResponses);
+
+ mockMvc.perform(get("/api/articles" + "?author=kms"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.articles[0]", Matchers.notNullValue(ArticleResponse.class)))
+ .andExpect(jsonPath("$.articles[0].title",Matchers.equalTo(articleResponses.get(0).getTitle())))
+ .andExpect(jsonPath("$.articles[0].description",Matchers.equalTo(articleResponses.get(0).getDescription())))
+ .andExpect(jsonPath("$.articles[0].body",Matchers.equalTo(articleResponses.get(0).getBody())))
+ .andExpect(jsonPath("$.articles[0].slug",Matchers.equalTo(articleResponses.get(0).getSlug())))
+ .andExpect(jsonPath("$.articles[0].tagList",Matchers.equalTo(articleResponses.get(0).getTagList())));
+ }
+
+ @WithAuthUser
+ @Test
+ @DisplayName("팔로우한 유저 게시글 가져오기 컨트롤러 테스트")
+ void getFeed() throws Exception{
+ List articleResponses = List.of(articleResponse);
+ when(articleService.getFeed(any(UserAuth.class), any(FeedParam.class))).thenReturn(articleResponses);
+
+ mockMvc.perform(get("/api/articles/feed"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.articles[0]", Matchers.notNullValue(ArticleResponse.class)))
+ .andExpect(jsonPath("$.articles[0].title",Matchers.equalTo(articleResponses.get(0).getTitle())))
+ .andExpect(jsonPath("$.articles[0].description",Matchers.equalTo(articleResponses.get(0).getDescription())))
+ .andExpect(jsonPath("$.articles[0].body",Matchers.equalTo(articleResponses.get(0).getBody())))
+ .andExpect(jsonPath("$.articles[0].slug",Matchers.equalTo(articleResponses.get(0).getSlug())))
+ .andExpect(jsonPath("$.articles[0].tagList",Matchers.equalTo(articleResponses.get(0).getTagList())));
+ }
+
@WithAuthUser(email = "test@gmail.com", username = "kms", id = 1L)
@Test
@DisplayName("게시글 만들기 컨트롤러 테스트")
diff --git a/src/test/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImplTest.java b/src/test/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImplTest.java
index 439383d..b3f53cf 100644
--- a/src/test/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImplTest.java
+++ b/src/test/java/com/io/realworld/domain/aggregate/article/service/ArticleServiceImplTest.java
@@ -1,32 +1,36 @@
package com.io.realworld.domain.aggregate.article.service;
-import com.io.realworld.domain.aggregate.article.dto.ArticleResponse;
-import com.io.realworld.domain.aggregate.article.dto.ArticleUpdate;
-import com.io.realworld.domain.aggregate.article.dto.Articledto;
+import com.io.realworld.domain.aggregate.article.dto.*;
import com.io.realworld.domain.aggregate.article.entity.Article;
import com.io.realworld.domain.aggregate.article.entity.Favorite;
import com.io.realworld.domain.aggregate.article.repository.ArticleRepository;
import com.io.realworld.domain.aggregate.article.repository.FavoriteRepository;
import com.io.realworld.domain.aggregate.profile.dto.ProfileResponse;
+import com.io.realworld.domain.aggregate.profile.entity.Follow;
+import com.io.realworld.domain.aggregate.profile.repository.ProfileRepository;
import com.io.realworld.domain.aggregate.profile.service.ProfileService;
+import com.io.realworld.domain.aggregate.tag.entity.Tag;
import com.io.realworld.domain.aggregate.tag.service.TagService;
import com.io.realworld.domain.aggregate.user.dto.UserAuth;
import com.io.realworld.domain.aggregate.user.entity.User;
import com.io.realworld.domain.aggregate.user.repository.UserRepository;
import com.io.realworld.exception.CustomException;
import com.io.realworld.exception.Error;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -36,6 +40,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
+
@ExtendWith(MockitoExtension.class)
class ArticleServiceImplTest {
@@ -57,6 +62,72 @@ class ArticleServiceImplTest {
@Mock
ProfileService profileService;
+ @Mock
+ ProfileRepository profileRepository;
+
+
+ @Test
+ @DisplayName("sv: 게시글들 가져오기 - tag가 일치")
+ void getArticlesTag(){
+ UserAuth userAuth = UserAuth.builder().id(1L).username("kms").build();
+ List articles = new ArrayList(){{
+ add(articlesListGet().get(0));
+ }};
+ ArticleParam articleParam = new ArticleParam();
+ articleParam.setTag("blogTag");
+
+ when(profileService.getProfile(eq(userAuth), any(String.class))).thenReturn(ProfileResponse.builder().username(articles.get(0).getAuthor().getUsername()).build());
+ when(articleRepository.findByTag(eq(articleParam.getTag()),any(Pageable.class))).thenReturn(articles);
+ List articleResponses = articleService.getArticles(userAuth, articleParam);
+
+ assertThat(articleResponses.get(0).getTagList().get(0)).isEqualTo(articleParam.getTag());
+ }
+
+ @Test
+ @DisplayName("sv: 게시글들 가져오기 - author가 일치")
+ void getArticlesAuthor(){
+ UserAuth userAuth = UserAuth.builder().id(1L).username("kms").build();
+
+ ArticleParam articleParam = new ArticleParam();
+ articleParam.setAuthor("jyb");
+
+ List articles = articlesListGet().stream().filter(article -> {
+ return article.getAuthor().getUsername().equals(articleParam.getAuthor());
+ }).collect(Collectors.toList());
+
+
+ when(profileService.getProfile(eq(userAuth), any(String.class))).thenReturn(ProfileResponse.builder().username(articles.get(0).getAuthor().getUsername()).build());
+ when(articleRepository.findByAuthorName(eq(articleParam.getAuthor()),any(Pageable.class))).thenReturn(articles);
+ List articleResponses = articleService.getArticles(userAuth, articleParam);
+
+ assertThat(articleResponses.get(0).getAuthor().getUsername()).isEqualTo(articleParam.getAuthor());
+ }
+
+ @Test
+ @DisplayName("sv: 피드 게시글 가져오기 ")
+ void getFeed(){
+ UserAuth userAuth = UserAuth.builder().id(1L).username("kms").build();
+
+ FeedParam feedParam = new FeedParam();
+
+ Article article = articlesListGet().get(2);
+ List articles = new ArrayList<>(){{
+ add(article);
+ }};
+
+ List follows = new ArrayList(){{
+ add(Follow.builder().followee(User.builder().username("kms").build()).follower(User.builder().username("eden").build()).build());
+ }};
+
+ when(profileService.getProfile(eq(userAuth), any(String.class))).thenReturn(ProfileResponse.builder().username(articles.get(0).getAuthor().getUsername()).build());
+ when(profileRepository.findByFollowerId(any(Long.class))).thenReturn(follows);
+ when(articleRepository.findByAuthorName(any(String.class),any(Pageable.class))).thenReturn(articles);
+ List articleResponses = articleService.getFeed(userAuth, feedParam);
+
+ assertThat(articleResponses.get(0).getAuthor().getUsername()).isEqualTo(follows.get(0).getFollower().getUsername());
+ }
+
+
@Test
@DisplayName("sv: 게시글 만들기 성공")
void createArticle() {
@@ -397,6 +468,65 @@ class ArticleServiceImplTest {
}
+ List articlesListGet(){
+ List blogTags = new ArrayList(){{
+ add(Tag.builder().tagName("blogTag").build());
+ add(Tag.builder().tagName("tutorial").build());
+ }};
+ List dietTags = new ArrayList(){{
+ add(Tag.builder().tagName("dietTag").build());
+ add(Tag.builder().tagName("tutorial").build());
+ }};
+ Article blogPost = Article.builder()
+ .id(1L)
+ .slug("post-my-blog")
+ .author(User.builder()
+ .username("kms")
+ .image("blog image")
+ .bio("blog bio")
+ .email("kms@naver.com").build())
+ .body("blog Post very ez")
+ .tagList(blogTags)
+ .description("blog create")
+ .title("Post My Blog")
+ .build();
+
+ Article dietPost = Article.builder()
+ .id(2L)
+ .slug("post-week-diet")
+ .author(User.builder()
+ .username("jyb")
+ .image("diet image")
+ .bio("diet bio")
+ .email("jyb@naver.com").build())
+ .body("diet very hard")
+ .tagList(dietTags)
+ .description("blog create")
+ .title("Post week diet")
+ .build();
+
+ Article codePost = Article.builder()
+ .id(3L)
+ .slug("post-coding-test")
+ .author(User.builder()
+ .username("eden")
+ .image("programmer")
+ .bio("s")
+ .email("tesla@google.com").build())
+ .body("Tesla very nice")
+ .tagList(dietTags)
+ .description("realworldApp")
+ .title("post Coding Test")
+ .build();
+
+ List articles = new ArrayList(){{
+ add(blogPost);
+ add(dietPost);
+ add(codePost);
+ }};
+ return articles;
+ }
+
diff --git a/src/test/java/com/io/realworld/repository/UserRepositoryTest.java b/src/test/java/com/io/realworld/domain/aggregate/user/repository/UserRepositoryTest.java
similarity index 96%
rename from src/test/java/com/io/realworld/repository/UserRepositoryTest.java
rename to src/test/java/com/io/realworld/domain/aggregate/user/repository/UserRepositoryTest.java
index a07777e..2eae86f 100644
--- a/src/test/java/com/io/realworld/repository/UserRepositoryTest.java
+++ b/src/test/java/com/io/realworld/domain/aggregate/user/repository/UserRepositoryTest.java
@@ -1,4 +1,4 @@
-package com.io.realworld.repository;
+package com.io.realworld.domain.aggregate.user.repository;
import com.io.realworld.domain.aggregate.user.entity.User;
import com.io.realworld.domain.aggregate.user.repository.UserRepository;
diff --git a/src/test/java/com/io/realworld/service/UserServiceImplTest.java b/src/test/java/com/io/realworld/domain/aggregate/user/service/UserServiceImplTest.java
similarity index 99%
rename from src/test/java/com/io/realworld/service/UserServiceImplTest.java
rename to src/test/java/com/io/realworld/domain/aggregate/user/service/UserServiceImplTest.java
index 81e6fa8..5d0f02a 100644
--- a/src/test/java/com/io/realworld/service/UserServiceImplTest.java
+++ b/src/test/java/com/io/realworld/domain/aggregate/user/service/UserServiceImplTest.java
@@ -1,4 +1,4 @@
-package com.io.realworld.service;
+package com.io.realworld.domain.aggregate.user.service;
import com.io.realworld.domain.aggregate.user.dto.*;
import com.io.realworld.domain.aggregate.user.entity.User;