Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/automatic-erd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: ERD to GitHub Pages

on:
pull_request:
branches: [ "**" ]
paths: [ "**" ]
branches: [ "main", "develop" ]
paths: [ "src/main/resources/db/migration/**" ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Java
uses: actions/setup-java@v3
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/terraform-plan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ name: Terraform Plan on PR

on:
pull_request:
branches:
- main
- develop
branches: [ "main", "develop" ]
paths: [ "terraform/**", "terraform-bootstrap/**" ]

permissions:
contents: read
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
public record FilteredSearchResult(
String kakaoId,
String name,
String address,
String roadAddress,
String lotNumberAddress,
String category
) {
}
14 changes: 12 additions & 2 deletions src/main/java/eatda/controller/story/StoryController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import eatda.controller.web.auth.LoginMember;
import eatda.service.story.StoryService;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
Expand All @@ -28,8 +32,14 @@ public ResponseEntity<Void> registerStory(
}

@GetMapping("api/stories")
public ResponseEntity<StoriesResponse> getStories() {
public ResponseEntity<StoriesResponse> getStories(@RequestParam(defaultValue = "5") @Min(1) @Max(50) int size) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

return ResponseEntity.status(HttpStatus.OK)
.body(storyService.getPagedStoryPreviews());
.body(storyService.getPagedStoryPreviews(size));
}

@GetMapping("/api/stories/{storyId}")
public ResponseEntity<StoryResponse> getStory(@PathVariable long storyId) {
return ResponseEntity.status(HttpStatus.OK)
.body(storyService.getStory(storyId));
}
}
3 changes: 2 additions & 1 deletion src/main/java/eatda/controller/story/StoryResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ public record StoryResponse(
String storeKakaoId,
String category,
String storeName,
String storeAddress,
String storeDistrict,
String storeNeighborhood,
String description,
String imageUrl
) {
Expand Down
58 changes: 46 additions & 12 deletions src/main/java/eatda/domain/story/Story.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ public class Story extends AuditingEntity {
@Column(name = "store_name", nullable = false)
private String storeName;

@Column(name = "store_address", nullable = false)
private String storeAddress;
@Column(name = "store_road_address", nullable = false)
private String storeRoadAddress;

@Column(name = "store_lot_number_address", nullable = false)
private String storeLotNumberAddress;

@Column(name = "store_category", nullable = false)
private String storeCategory;
Expand All @@ -54,21 +57,23 @@ public class Story extends AuditingEntity {
private Story(
Member member,
String storeKakaoId,
String storeName,
String storeAddress,
String storeCategory,
String storeName,
String storeRoadAddress,
String storeLotNumberAddress,
String description,
String imageKey
) {
validateMember(member);
validateStore(storeKakaoId, storeName, storeAddress, storeCategory);
validateStore(storeKakaoId, storeCategory, storeName, storeRoadAddress, storeLotNumberAddress);
validateStory(description, imageKey);

this.member = member;
this.storeKakaoId = storeKakaoId;
this.storeName = storeName;
this.storeAddress = storeAddress;
this.storeCategory = storeCategory;
this.storeName = storeName;
this.storeRoadAddress = storeRoadAddress;
this.storeLotNumberAddress = storeLotNumberAddress;
this.description = description;
this.imageKey = imageKey;
}
Expand All @@ -79,11 +84,18 @@ private void validateMember(Member member) {
}
}

private void validateStore(String storeKakaoId, String storeName, String storeAddress, String storeCategory) {
private void validateStore(
String storeKakaoId,
String storeCategory,
String storeName,
String roadAddress,
String lotNumberAddress
) {
validateStoreKakaoId(storeKakaoId);
validateStoreName(storeName);
validateStoreAddress(storeAddress);
validateStoreCategory(storeCategory);
validateStoreName(storeName);
validateStoreRoadAddress(roadAddress);
validateStoreLotNumberAddress(lotNumberAddress);
}

private void validateStory(String description, String imageKey) {
Expand All @@ -103,8 +115,14 @@ private void validateStoreName(String storeName) {
}
}

private void validateStoreAddress(String storeAddress) {
if (storeAddress == null || storeAddress.isBlank()) {
private void validateStoreRoadAddress(String roadAddress) {
if (roadAddress == null || roadAddress.isBlank()) {
throw new BusinessException(BusinessErrorCode.INVALID_STORE_ADDRESS);
}
}

private void validateStoreLotNumberAddress(String lotNumberAddress) {
if (lotNumberAddress == null || lotNumberAddress.isBlank()) {
throw new BusinessException(BusinessErrorCode.INVALID_STORE_ADDRESS);
}
}
Expand All @@ -126,4 +144,20 @@ private void validateImage(String imageKey) {
throw new BusinessException(BusinessErrorCode.INVALID_STORY_IMAGE_KEY);
}
}

public String getAddressDistrict() {
String[] addressParts = storeLotNumberAddress.split(" ");
if (addressParts.length < 2) {
return "";
}
return addressParts[1];
}

public String getAddressNeighborhood() {
String[] addressParts = storeLotNumberAddress.split(" ");
if (addressParts.length < 3) {
return "";
}
return addressParts[2];
}
}
2 changes: 1 addition & 1 deletion src/main/java/eatda/exception/BusinessErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public enum BusinessErrorCode {
INVALID_STORY_IMAGE_KEY("STY002", "스토리 이미지 Key는 필수입니다."),
STORY_MEMBER_REQUIRED("STY003", "스토리 작성 시 회원 정보는 필수입니다."),
STORY_STORE_REQUIRED("STY004", "스토리 작성 시 가게 정보는 필수입니다."),
STORY_NOT_FOUND("STY005", "스토리를 찾을 수 없습니다."),
STORY_NOT_FOUND("STY005", "스토리를 찾을 수 없습니다.", HttpStatus.NOT_FOUND),
INVALID_STORE_ID("STY006", "유효하지 않은 가게 ID입니다."),
INVALID_STORE_KAKAO_ID("STY007", "스토어 Kakao ID는 필수입니다."),
INVALID_STORE_NAME("STY008", "스토어 이름은 필수입니다."),
Expand Down
26 changes: 22 additions & 4 deletions src/main/java/eatda/service/story/StoryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import eatda.controller.story.FilteredSearchResult;
import eatda.controller.story.StoriesResponse;
import eatda.controller.story.StoryRegisterRequest;
import eatda.controller.story.StoryResponse;
import eatda.domain.member.Member;
import eatda.domain.story.Story;
import eatda.exception.BusinessErrorCode;
Expand All @@ -26,7 +27,6 @@
@RequiredArgsConstructor
public class StoryService {
private static final int PAGE_START_NUMBER = 0;
private static final int PAGE_SIZE = 5;

private final StoreService storeService;
private final ImageService imageService;
Expand All @@ -44,7 +44,8 @@ public void registerStory(StoryRegisterRequest request, MultipartFile image, Lon
.member(member)
.storeKakaoId(matchedStore.kakaoId())
.storeName(matchedStore.name())
.storeAddress(matchedStore.address())
.storeRoadAddress(matchedStore.roadAddress())
.storeLotNumberAddress(matchedStore.lotNumberAddress())
.storeCategory(matchedStore.category())
.description(request.description())
.imageKey(imageKey)
Expand All @@ -61,14 +62,15 @@ private FilteredSearchResult filteredSearchResponse(List<StoreSearchResult> resp
store.kakaoId(),
store.name(),
store.roadAddress(),
store.lotNumberAddress(),
store.categoryName()
))
.orElseThrow(() -> new BusinessException(BusinessErrorCode.STORE_NOT_FOUND));
}

@Transactional(readOnly = true)
public StoriesResponse getPagedStoryPreviews() {
Pageable pageable = PageRequest.of(PAGE_START_NUMBER, PAGE_SIZE);
public StoriesResponse getPagedStoryPreviews(int size) {
Pageable pageable = PageRequest.of(PAGE_START_NUMBER, size);
Comment on lines +72 to +73
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[제안] Pageable에 이런 게 있더라구요!

Suggested change
public StoriesResponse getPagedStoryPreviews(int size) {
Pageable pageable = PageRequest.of(PAGE_START_NUMBER, size);
public StoriesResponse getPagedStoryPreviews(int size) {
Pageable pageable = PageRequest.of(Pageable.ofSize(size));

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 제안 감사합니다!
컴파일 에러가 나는데 어엄.. 이 방식을 말씀하신거겠죠??
Pageable pageable = Pageable.ofSize(size);

1차 배포후에 다른 페이지가 필요하다고 할수도 있으니... 지금은 이대로 가겠습니다!

Page<Story> orderByPage = storyRepository.findAllByOrderByCreatedAtDesc(pageable);

return new StoriesResponse(
Expand All @@ -80,4 +82,20 @@ public StoriesResponse getPagedStoryPreviews() {
.toList()
);
}

@Transactional(readOnly = true)
public StoryResponse getStory(long storyId) {
Story story = storyRepository.findById(storyId)
.orElseThrow(() -> new BusinessException(BusinessErrorCode.STORY_NOT_FOUND));

return new StoryResponse(
story.getStoreKakaoId(),
story.getStoreCategory(),
story.getStoreName(),
story.getAddressDistrict(),
story.getAddressNeighborhood(),
story.getDescription(),
imageService.getPresignedUrl(story.getImageKey())
);
}
}
19 changes: 10 additions & 9 deletions src/main/resources/db/migration/V3__add_story_table.sql
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
CREATE TABLE `story`
(
`id` BIGINT NOT NULL AUTO_INCREMENT,
`member_id` BIGINT NOT NULL,
`store_kakao_id` VARCHAR(255) NOT NULL,
`store_name` VARCHAR(255) NOT NULL,
`store_address` VARCHAR(255) NOT NULL,
`store_category` VARCHAR(50) NOT NULL,
`description` TEXT NOT NULL,
`image_key` VARCHAR(511) NOT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`id` BIGINT NOT NULL AUTO_INCREMENT,
`member_id` BIGINT NOT NULL,
`store_kakao_id` VARCHAR(255) NOT NULL,
`store_name` VARCHAR(255) NOT NULL,
`store_road_address` VARCHAR(255) NOT NULL,
`store_lot_number_address` VARCHAR(255) NOT NULL,
`store_category` VARCHAR(50) NOT NULL,
`description` TEXT NOT NULL,
`image_key` VARCHAR(511) NOT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
20 changes: 10 additions & 10 deletions src/main/resources/db/seed/dev/V2__dev_init_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ VALUES (1, '99999999999', 'KOREAN', '01012345678', '맛있는 한식집', 'https
'서울시 강남구 역삼동 222-324', 37.5036675804016, 127.05305858911);

INSERT INTO cheer (id, member_id, store_id, description, image_key, is_admin)
VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'default.jpg', true),
(2, 2, 2, '서비스가 훌륭해요!', 'default.jpg', true),
(3, 3, 3, '여기 음식이 정말 맛있어요!', 'default.jpg', true),
(4, 4, 4, '분위기가 너무 좋아요!', 'default.jpg', true),
(5, 5, 5, '디저트가 정말 맛있어요!', 'default.jpg', true),
(6, 6, 6, '커피가 정말 맛있어요!', 'default.jpg', false),
(7, 7, 7, '패스트푸드가 빠르고 맛있어요!', 'default.jpg', false);
VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'cheer/dummy/1.jpg', true),
(2, 2, 2, '서비스가 훌륭해요!', 'cheer/dummy/2.jpg', true),
(3, 3, 3, '여기 음식이 정말 맛있어요!', 'cheer/dummy/3.jpg', true),
(4, 4, 4, '분위기가 너무 좋아요!', 'cheer/dummy/4.jpg', true),
(5, 5, 5, '디저트가 정말 맛있어요!', 'cheer/dummy/5.jpg', true),
(6, 6, 6, '커피가 정말 맛있어요!', 'cheer/dummy/6.jpg', false),
(7, 7, 7, '패스트푸드가 빠르고 맛있어요!', 'cheer/dummy/7.jpg', false);

INSERT INTO article (id, title, subtitle, article_url, image_key)
VALUES (1, '첫 번째 기사', '서브타이틀 1', 'https://example.com/article1', 'default.jpg'),
(2, '두 번째 기사', '서브타이틀 2', 'https://example.com/article2', 'default.jpg'),
(3, '세 번째 기사', '서브타이틀 3', 'https://example.com/article3', 'default.jpg');
VALUES (1, '첫 번째 기사', '서브타이틀 1', 'https://example.com/article1', 'article/dummy/1.jpg'),
(2, '두 번째 기사', '서브타이틀 2', 'https://example.com/article2', 'article/dummy/2.jpg'),
(3, '세 번째 기사', '서브타이틀 3', 'https://example.com/article3', 'article/dummy/3.jpg');
19 changes: 14 additions & 5 deletions src/main/resources/db/seed/dev/V4__dev_add_story_data.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
INSERT INTO story (member_id, store_kakao_id, store_name, store_address,
store_category, description, image_key)
VALUES (1, '99999999999', '맛있는 한식집', '서울시 강남구 역삼동 123-45', 'KOREAN', '진짜 여기 곱창 맛집임. 다시 또 갈 듯!', 'story/preview/1.jpg'),
(2, '99999999998', '아름다운 양식집', '서울시 강남구 역삼동 67-89', 'WESTERN', '스테이크가 부드럽고 서비스도 좋아요.', 'story/preview/2.jpg'),
(3, '99999999997', '정통 중식당', '서울시 강남구 역삼동 101-112', 'CHINESE', '짜장면이 정통의 맛. 강력 추천.', 'story/preview/3.jpg');
INSERT INTO story (member_id,
store_kakao_id,
store_name,
store_road_address,
store_lot_number_address,
store_category,
description,
image_key)
VALUES (1, '99999999999', '맛있는 한식집', '서울시 강남구 테헤란로 123', '서울시 강남구 역삼동 123-45', 'KOREAN', '진짜 여기 곱창 맛집임. 다시 또 갈 듯!',
'story/dummy/1.jpg'),
(2, '99999999998', '아름다운 양식집', '서울시 강남구 테헤란로 67', '서울시 강남구 역삼동 67-89', 'WESTERN', '스테이크가 부드럽고 서비스도 좋아요.',
'story/dummy/2.jpg'),
(3, '99999999997', '정통 중식당', '서울시 강남구 봉은사로 101', '서울시 강남구 역삼동 101-112', 'CHINESE', '짜장면이 정통의 맛. 강력 추천.',
'story/dummy/3.jpg');
20 changes: 10 additions & 10 deletions src/main/resources/db/seed/local/V2__local_init_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ VALUES (1, '99999999999', 'KOREAN', '01012345678', '맛있는 한식집', 'https
'서울시 강남구 역삼동 222-324', 37.5036675804016, 127.05305858911);

INSERT INTO cheer (id, member_id, store_id, description, image_key, is_admin)
VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'default.jpg', true),
(2, 2, 2, '서비스가 훌륭해요!', 'default.jpg', true),
(3, 3, 3, '여기 음식이 정말 맛있어요!', 'default.jpg', true),
(4, 4, 4, '분위기가 너무 좋아요!', 'default.jpg', true),
(5, 5, 5, '디저트가 정말 맛있어요!', 'default.jpg', true),
(6, 6, 6, '커피가 정말 맛있어요!', 'default.jpg', false),
(7, 7, 7, '패스트푸드가 빠르고 맛있어요!', 'default.jpg', false);
VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'cheer/dummy/1.jpg', true),
(2, 2, 2, '서비스가 훌륭해요!', 'cheer/dummy/2.jpg', true),
(3, 3, 3, '여기 음식이 정말 맛있어요!', 'cheer/dummy/3.jpg', true),
(4, 4, 4, '분위기가 너무 좋아요!', 'cheer/dummy/4.jpg', true),
(5, 5, 5, '디저트가 정말 맛있어요!', 'cheer/dummy/5.jpg', true),
(6, 6, 6, '커피가 정말 맛있어요!', 'cheer/dummy/6.jpg', false),
(7, 7, 7, '패스트푸드가 빠르고 맛있어요!', 'cheer/dummy/7.jpg', false);

INSERT INTO article (id, title, subtitle, article_url, image_key)
VALUES (1, '첫 번째 기사', '서브타이틀 1', 'https://example.com/article1', 'default.jpg'),
(2, '두 번째 기사', '서브타이틀 2', 'https://example.com/article2', 'default.jpg'),
(3, '세 번째 기사', '서브타이틀 3', 'https://example.com/article3', 'default.jpg');
VALUES (1, '첫 번째 기사', '서브타이틀 1', 'https://example.com/article1', 'article/dummy/1.jpg'),
(2, '두 번째 기사', '서브타이틀 2', 'https://example.com/article2', 'article/dummy/2.jpg'),
(3, '세 번째 기사', '서브타이틀 3', 'https://example.com/article3', 'article/dummy/3.jpg');
31 changes: 22 additions & 9 deletions src/main/resources/db/seed/local/V4__local_add_story_data.sql
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
INSERT INTO story (member_id, store_kakao_id, store_name, store_address,
store_category, description, image_key)
VALUES (1, '99999999999', '맛있는 한식집', '서울시 강남구 역삼동 123-45', 'KOREAN', '진짜 여기 곱창 맛집임. 다시 또 갈 듯!', 'story/preview/1.jpg'),
(2, '99999999998', '아름다운 양식집', '서울시 강남구 역삼동 67-89', 'WESTERN', '스테이크가 부드럽고 서비스도 좋아요.', 'story/preview/2.jpg'),
(3, '99999999997', '정통 중식당', '서울시 강남구 역삼동 101-112', 'CHINESE', '짜장면이 정통의 맛. 강력 추천.', 'story/preview/3.jpg'),
(4, '99999999996', '고급 양식 레스토랑', '서울시 강남구 역삼동 131-415', 'WESTERN', '분위기가 연인 데이트하기 좋아요.', 'story/preview/4.jpg'),
(5, '99999999995', '달콤한 디저트 카페', '서울시 강남구 역삼동 161-718', 'ETC', '케이크가 촉촉하고 맛있어요.', 'story/preview/5.jpg'),
(6, '99999999994', '아늑한 카페', '서울시 강남구 역삼동 192-021', 'ETC', '조용해서 공부하기 좋아요.', 'story/preview/6.jpg'),
(7, '99999999993', '빠른 패스트푸드점', '서울시 강남구 역삼동 222-324', 'ETC', '햄버거 나오는데 3분도 안 걸림. 굿.', 'story/preview/7.jpg');
INSERT INTO story (member_id,
store_kakao_id,
store_name,
store_road_address,
store_lot_number_address,
store_category,
description,
image_key)
VALUES (1, '99999999999', '맛있는 한식집', '서울시 강남구 테헤란로 123', '서울시 강남구 역삼동 123-45', 'KOREAN', '진짜 여기 곱창 맛집임. 다시 또 갈 듯!',
'story/dummy/1.jpg'),
(2, '99999999998', '아름다운 양식집', '서울시 강남구 테헤란로 67', '서울시 강남구 역삼동 67-89', 'WESTERN', '스테이크가 부드럽고 서비스도 좋아요.',
'story/dummy/2.jpg'),
(3, '99999999997', '정통 중식당', '서울시 강남구 봉은사로 101', '서울시 강남구 역삼동 101-112', 'CHINESE', '짜장면이 정통의 맛. 강력 추천.',
'story/dummy/3.jpg'),
(4, '99999999996', '고급 양식 레스토랑', '서울시 강남구 언주로 131', '서울시 강남구 역삼동 131-415', 'WESTERN', '분위기가 연인 데이트하기 좋아요.',
'story/dummy/4.jpg'),
(5, '99999999995', '달콤한 디저트 카페', '서울시 강남구 논현로 161', '서울시 강남구 역삼동 161-718', 'ETC', '케이크가 촉촉하고 맛있어요.',
'story/dummy/5.jpg'),
(6, '99999999994', '아늑한 카페', '서울시 강남구 선릉로 192', '서울시 강남구 역삼동 192-021', 'ETC', '조용해서 공부하기 좋아요.',
'story/dummy/6.jpg'),
(7, '99999999993', '빠른 패스트푸드점', '서울시 강남구 도산대로 222', '서울시 강남구 역삼동 222-324', 'ETC', '햄버거 나오는데 3분도 안 걸림. 굿.',
'story/dummy/7.jpg');
Loading