Skip to content

Commit 8d683aa

Browse files
authored
Merge pull request #159 from YAPP-Github/feat/PRODUCT-238
[Feat] '응원 등록 API'에 응원 태그 추가
2 parents 701abe0 + fb898f6 commit 8d683aa

File tree

9 files changed

+100
-23
lines changed

9 files changed

+100
-23
lines changed
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
package eatda.controller.cheer;
22

3+
import eatda.domain.cheer.CheerTagName;
4+
import java.util.Collections;
5+
import java.util.List;
6+
37
public record CheerRegisterRequest(
48
String storeKakaoId,
59
String storeName,
6-
String description
10+
String description,
11+
List<CheerTagName> tags
712
) {
13+
14+
@Override
15+
public List<CheerTagName> tags() { // TODO : 클라이언트 태그 구현 완료 시 삭제
16+
if (tags == null) {
17+
return Collections.emptyList();
18+
}
19+
return tags;
20+
}
821
}
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
package eatda.controller.cheer;
22

33
import eatda.domain.cheer.Cheer;
4+
import eatda.domain.cheer.CheerTag;
5+
import eatda.domain.cheer.CheerTagName;
46
import eatda.domain.store.Store;
7+
import java.util.List;
58

69
public record CheerResponse(
710
long storeId,
811
long cheerId,
912
String imageUrl,
10-
String cheerDescription
13+
String cheerDescription,
14+
List<CheerTagName> tags
1115
) {
1216

13-
public CheerResponse(Cheer cheer, String imageUrl, Store store) {
17+
public CheerResponse(Cheer cheer, List<CheerTag> cheerTags, Store store, String imageUrl) {
1418
this(
1519
store.getId(),
1620
cheer.getId(),
1721
imageUrl,
18-
cheer.getDescription()
22+
cheer.getDescription(),
23+
toTagNames(cheerTags)
1924
);
2025
}
26+
27+
private static List<CheerTagName> toTagNames(List<CheerTag> cheerTags) {
28+
return cheerTags.stream()
29+
.map(CheerTag::getName)
30+
.toList();
31+
}
2132
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package eatda.repository.cheer;
2+
3+
import eatda.domain.cheer.CheerTag;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface CheerTagRepository extends JpaRepository<CheerTag, Long> {
7+
8+
}

src/main/java/eatda/service/cheer/CheerService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88
import eatda.controller.cheer.CheersResponse;
99
import eatda.domain.ImageKey;
1010
import eatda.domain.cheer.Cheer;
11+
import eatda.domain.cheer.CheerTag;
12+
import eatda.domain.cheer.CheerTagNames;
1113
import eatda.domain.member.Member;
1214
import eatda.domain.store.Store;
1315
import eatda.domain.store.StoreSearchResult;
1416
import eatda.exception.BusinessErrorCode;
1517
import eatda.exception.BusinessException;
1618
import eatda.repository.cheer.CheerRepository;
19+
import eatda.repository.cheer.CheerTagRepository;
1720
import eatda.repository.member.MemberRepository;
1821
import eatda.repository.store.StoreRepository;
1922
import eatda.storage.image.ImageStorage;
@@ -32,20 +35,23 @@ public class CheerService {
3235
private final MemberRepository memberRepository;
3336
private final StoreRepository storeRepository;
3437
private final CheerRepository cheerRepository;
38+
private final CheerTagRepository cheerTagRepository;
3539
private final ImageStorage imageStorage;
3640

3741
@Transactional
3842
public CheerResponse registerCheer(CheerRegisterRequest request,
3943
StoreSearchResult result,
4044
ImageKey imageKey,
4145
long memberId) {
46+
CheerTagNames cheerTagNames = new CheerTagNames(request.tags());
4247
Member member = memberRepository.getById(memberId);
4348
validateRegisterCheer(member, request.storeKakaoId());
4449

4550
Store store = storeRepository.findByKakaoId(result.kakaoId())
4651
.orElseGet(() -> storeRepository.save(result.toStore())); // TODO 상점 조회/저장 동시성 이슈 해결
4752
Cheer cheer = cheerRepository.save(new Cheer(member, store, request.description(), imageKey));
48-
return new CheerResponse(cheer, imageStorage.getPreSignedUrl(imageKey), store);
53+
List<CheerTag> cheerTags = cheerTagRepository.saveAll(cheerTagNames.toCheerTags(cheer));
54+
return new CheerResponse(cheer, cheerTags, store, imageStorage.getPreSignedUrl(imageKey));
4955
}
5056

5157
private void validateRegisterCheer(Member member, String storeKakaoId) {

src/test/java/eatda/controller/BaseControllerTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import eatda.fixture.StoreGenerator;
1919
import eatda.fixture.StoryGenerator;
2020
import eatda.repository.cheer.CheerRepository;
21+
import eatda.repository.cheer.CheerTagRepository;
2122
import eatda.repository.member.MemberRepository;
2223
import eatda.repository.store.StoreRepository;
2324
import eatda.repository.story.StoryRepository;
@@ -71,6 +72,9 @@ public class BaseControllerTest {
7172
@Autowired
7273
protected CheerRepository cheerRepository;
7374

75+
@Autowired
76+
protected CheerTagRepository cheerTagRepository;
77+
7478
@Autowired
7579
protected StoryRepository storyRepository;
7680

src/test/java/eatda/controller/cheer/CheerControllerTest.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66
import eatda.controller.BaseControllerTest;
77
import eatda.domain.cheer.Cheer;
8+
import eatda.domain.cheer.CheerTagName;
89
import eatda.domain.member.Member;
910
import eatda.domain.store.District;
1011
import eatda.domain.store.Store;
1112
import eatda.util.ImageUtils;
1213
import eatda.util.MappingUtils;
1314
import java.time.LocalDateTime;
15+
import java.util.List;
1416
import org.junit.jupiter.api.Nested;
1517
import org.junit.jupiter.api.Test;
1618
import org.springframework.http.HttpHeaders;
@@ -22,8 +24,9 @@ class RegisterCheer {
2224

2325
@Test
2426
void 응원을_등록한다() {
25-
Store store = storeGenerator.generate("123", "서울시 노원구 월계3동 123-45", District.NOWON);
26-
CheerRegisterRequest request = new CheerRegisterRequest(store.getKakaoId(), store.getName(), "맛있어요!");
27+
Store store = storeGenerator.generate("123", "서울시 노원구 월계3동 123-45");
28+
CheerRegisterRequest request = new CheerRegisterRequest(store.getKakaoId(), store.getName(), "맛있어요!",
29+
List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM));
2730

2831
CheerResponse response = given()
2932
.header(HttpHeaders.AUTHORIZATION, accessToken())
@@ -36,13 +39,18 @@ class RegisterCheer {
3639
.statusCode(201)
3740
.extract().as(CheerResponse.class);
3841

39-
assertThat(response.storeId()).isEqualTo(store.getId());
42+
assertAll(
43+
() -> assertThat(response.storeId()).isEqualTo(store.getId()),
44+
() -> assertThat(response.cheerDescription()).isEqualTo(request.description()),
45+
() -> assertThat(response.tags()).containsExactlyInAnyOrderElementsOf(request.tags())
46+
);
4047
}
4148

4249
@Test
4350
void 이미지가_비어있을_경우에도_응원을_등록한다() {
4451
Store store = storeGenerator.generate("123", "서울시 노원구 월계3동 123-45", District.NOWON);
45-
CheerRegisterRequest request = new CheerRegisterRequest(store.getKakaoId(), store.getName(), "맛있어요!");
52+
CheerRegisterRequest request = new CheerRegisterRequest(store.getKakaoId(), store.getName(), "맛있어요!",
53+
List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM));
4654

4755
CheerResponse response = given()
4856
.header(HttpHeaders.AUTHORIZATION, accessToken())
@@ -54,7 +62,11 @@ class RegisterCheer {
5462
.statusCode(201)
5563
.extract().as(CheerResponse.class);
5664

57-
assertThat(response.storeId()).isEqualTo(store.getId());
65+
assertAll(
66+
() -> assertThat(response.storeId()).isEqualTo(store.getId()),
67+
() -> assertThat(response.cheerDescription()).isEqualTo(request.description()),
68+
() -> assertThat(response.tags()).containsExactlyInAnyOrderElementsOf(request.tags())
69+
);
5870
}
5971
}
6072

src/test/java/eatda/document/store/CheerDocumentTest.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import eatda.document.RestDocsRequest;
2424
import eatda.document.RestDocsResponse;
2525
import eatda.document.Tag;
26+
import eatda.domain.cheer.CheerTagName;
2627
import eatda.exception.BusinessErrorCode;
2728
import eatda.exception.BusinessException;
2829
import eatda.util.ImageUtils;
@@ -67,21 +68,25 @@ class RegisterCheer {
6768
).requestBodyField("request",
6869
fieldWithPath("storeKakaoId").type(STRING).description("가게 카카오 ID"),
6970
fieldWithPath("storeName").type(STRING).description("가게 이름"),
70-
fieldWithPath("description").type(STRING).description("응원 내용")
71+
fieldWithPath("description").type(STRING).description("응원 내용"),
72+
fieldWithPath("tags").type(ARRAY).description("응원 태그 목록")
7173
);
7274

7375
RestDocsResponse responseDocument = response()
7476
.responseBodyField(
7577
fieldWithPath("storeId").type(NUMBER).description("가게 ID"),
7678
fieldWithPath("cheerId").type(NUMBER).description("응원 ID"),
7779
fieldWithPath("imageUrl").type(STRING).description("이미지 URL").optional(),
78-
fieldWithPath("cheerDescription").type(STRING).description("응원 내용")
80+
fieldWithPath("cheerDescription").type(STRING).description("응원 내용"),
81+
fieldWithPath("tags").type(ARRAY).description("응원 태그 목록")
7982
);
8083

8184
@Test
8285
void 응원_등록_성공() {
83-
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "너무 맛있어요!");
84-
CheerResponse response = new CheerResponse(1L, 1L, "https://example.img", "너무 맛있어요!");
86+
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "너무 맛있어요!",
87+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
88+
CheerResponse response = new CheerResponse(1L, 1L, "https://example.img", "너무 맛있어요!",
89+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
8590
doReturn(response).when(cheerService).registerCheer(eq(request), any(), any(), anyLong());
8691

8792
var document = document("cheer/register", 201)
@@ -110,7 +115,8 @@ class RegisterCheer {
110115
"INVALID_CHEER_DESCRIPTION"})
111116
@ParameterizedTest
112117
void 응원_등록_실패(BusinessErrorCode errorCode) {
113-
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "너무 맛있어요!");
118+
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "너무 맛있어요!",
119+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
114120
doThrow(new BusinessException(errorCode))
115121
.when(cheerService).registerCheer(eq(request), any(), any(), anyLong());
116122

src/test/java/eatda/service/BaseServiceTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import eatda.fixture.MemberGenerator;
1212
import eatda.fixture.StoreGenerator;
1313
import eatda.repository.cheer.CheerRepository;
14+
import eatda.repository.cheer.CheerTagRepository;
1415
import eatda.repository.member.MemberRepository;
1516
import eatda.repository.store.StoreRepository;
1617
import eatda.repository.story.StoryRepository;
@@ -67,6 +68,9 @@ public abstract class BaseServiceTest {
6768
@Autowired
6869
protected CheerRepository cheerRepository;
6970

71+
@Autowired
72+
protected CheerTagRepository cheerTagRepository;
73+
7074
@Autowired
7175
protected StoryRepository storyRepository;
7276

src/test/java/eatda/service/cheer/CheerServiceTest.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import eatda.controller.cheer.CheersResponse;
1111
import eatda.domain.ImageKey;
1212
import eatda.domain.cheer.Cheer;
13+
import eatda.domain.cheer.CheerTagName;
1314
import eatda.domain.member.Member;
1415
import eatda.domain.store.District;
1516
import eatda.domain.store.Store;
@@ -19,6 +20,7 @@
1920
import eatda.exception.BusinessException;
2021
import eatda.service.BaseServiceTest;
2122
import java.time.LocalDateTime;
23+
import java.util.List;
2224
import org.junit.jupiter.api.Nested;
2325
import org.junit.jupiter.api.Test;
2426
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,7 +43,8 @@ class RegisterCheer {
4143
cheerGenerator.generateCommon(member, store2);
4244
cheerGenerator.generateCommon(member, store3);
4345

44-
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "추가 응원");
46+
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "추가 응원",
47+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
4548
StoreSearchResult result = new StoreSearchResult(
4649
"123", StoreCategory.KOREAN, "02-755-5232", "농민백암순대 본점", "http://place.map.kakao.com/123",
4750
"서울시 강남구 역삼동 123-45", "서울시 강남구 역삼동 123-45", District.GANGNAM, 37.5665, 126.9780);
@@ -59,7 +62,8 @@ class RegisterCheer {
5962
Store store = storeGenerator.generate("123", "서울시 강남구 역삼동 123-45");
6063
cheerGenerator.generateCommon(member, store);
6164

62-
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "추가 응원");
65+
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "추가 응원",
66+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
6367
StoreSearchResult result = new StoreSearchResult(
6468
"123", StoreCategory.KOREAN, "02-755-5232", "농민백암순대 본점", "http://place.map.kakao.com/123",
6569
"서울시 강남구 역삼동 123-45", "서울시 강남구 역삼동 123-45", District.GANGNAM, 37.5665, 126.9780);
@@ -75,7 +79,8 @@ class RegisterCheer {
7579
void 해당_응원의_가게가_저장되어_있지_않다면_가게와_응원을_저장한다() {
7680
Member member = memberGenerator.generate("123");
7781

78-
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "맛있어요!");
82+
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "맛있어요!",
83+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
7984
StoreSearchResult result = new StoreSearchResult(
8085
"123", StoreCategory.KOREAN, "02-755-5232", "농민백암순대 본점", "http://place.map.kakao.com/123",
8186
"서울시 강남구 역삼동 123-45", "서울시 강남구 역삼동 123-45", District.GANGNAM, 37.5665, 126.9780);
@@ -87,7 +92,9 @@ class RegisterCheer {
8792
assertAll(
8893
() -> assertThat(response.storeId()).isEqualTo(foundStore.getId()),
8994
() -> assertThat(response.cheerDescription()).isEqualTo("맛있어요!"),
90-
() -> assertThat(response.imageUrl()).isNotNull()
95+
() -> assertThat(response.imageUrl()).isNotNull(),
96+
() -> assertThat(response.tags()).containsExactlyInAnyOrder(
97+
CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM)
9198
);
9299
}
93100

@@ -96,7 +103,8 @@ class RegisterCheer {
96103
Member member = memberGenerator.generate("123");
97104
Store store = storeGenerator.generate("123", "서울시 강남구 역삼동 123-45");
98105

99-
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "맛있어요!");
106+
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "맛있어요!",
107+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
100108
StoreSearchResult result = new StoreSearchResult(
101109
"123", StoreCategory.KOREAN, "02-755-5232", "농민백암순대 본점", "http://place.map.kakao.com/123",
102110
"서울시 강남구 역삼동 123-45", "서울시 강남구 역삼동 123-45", District.GANGNAM, 37.5665, 126.9780);
@@ -109,15 +117,18 @@ class RegisterCheer {
109117
() -> assertThat(foundStore.getId()).isEqualTo(store.getId()),
110118
() -> assertThat(response.storeId()).isEqualTo(foundStore.getId()),
111119
() -> assertThat(response.cheerDescription()).isEqualTo("맛있어요!"),
112-
() -> assertThat(response.imageUrl()).isNotNull()
120+
() -> assertThat(response.imageUrl()).isNotNull(),
121+
() -> assertThat(response.tags()).containsExactlyInAnyOrder(
122+
CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM)
113123
);
114124
}
115125

116126
@Test
117127
void 해당_응원의_이미지가_비어있어도_응원을_저장할_수_있다() {
118128
Member member = memberGenerator.generate("123");
119129

120-
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "맛있어요!");
130+
CheerRegisterRequest request = new CheerRegisterRequest("123", "농민백암순대 본점", "맛있어요!",
131+
List.of(CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM));
121132
StoreSearchResult result = new StoreSearchResult(
122133
"123", StoreCategory.KOREAN, "02-755-5232", "농민백암순대 본점", "http://place.map.kakao.com/123",
123134
"서울시 강남구 역삼동 123-45", "서울시 강남구 역삼동 123-45", District.GANGNAM, 37.5665, 126.9780);
@@ -129,7 +140,9 @@ class RegisterCheer {
129140
assertAll(
130141
() -> assertThat(response.storeId()).isEqualTo(foundStore.getId()),
131142
() -> assertThat(response.cheerDescription()).isEqualTo("맛있어요!"),
132-
() -> assertThat(response.imageUrl()).isNull()
143+
() -> assertThat(response.imageUrl()).isNull(),
144+
() -> assertThat(response.tags()).containsExactlyInAnyOrder(
145+
CheerTagName.GOOD_FOR_DATING, CheerTagName.CLEAN_RESTROOM)
133146
);
134147
}
135148
}

0 commit comments

Comments
 (0)