diff --git a/dateroad-api/src/main/java/org/dateroad/DateroadApplication.java b/dateroad-api/src/main/java/org/dateroad/DateroadApplication.java index 6dc43398..386cd289 100644 --- a/dateroad-api/src/main/java/org/dateroad/DateroadApplication.java +++ b/dateroad-api/src/main/java/org/dateroad/DateroadApplication.java @@ -2,7 +2,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; @SpringBootApplication public class DateroadApplication { diff --git a/dateroad-api/src/main/java/org/dateroad/advertisement/api/AdvertisementApi.java b/dateroad-api/src/main/java/org/dateroad/advertisement/api/AdvertisementApi.java new file mode 100644 index 00000000..83ba2829 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/advertisement/api/AdvertisementApi.java @@ -0,0 +1,144 @@ +package org.dateroad.advertisement.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.dateroad.advertisement.dto.response.AdvGetAllRes; +import org.dateroad.advertisement.dto.response.AdvGetDetailRes; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; + +@Tag(name = "광고 관련 API") +@SecurityRequirement(name = "Authorization") +public interface AdvertisementApi { + @Operation( + summary = "광고 전체 조회 API", + responses = { + @ApiResponse( + responseCode = "200", + content = @Content( + schema = @Schema(implementation = AdvGetAllRes.class), + examples = @ExampleObject(value = """ + { + "advertismentDtoResList": [ + { + "advertismentId": 1, + "thumbnail": "http://example.com/thumbnail1.jpg", + "title": "광고 제목 1", + }, + { + "advertismentId": 2, + "thumbnail": "http://example.com/thumbnail2.jpg", + "title": "광고 제목 2", + }, + { + "advertismentId": 3, + "thumbnail": "http://example.com/thumbnail2.jpg", + "title": "광고 제목 3", + }, + { + "advertismentId": 4, + "thumbnail": "http://example.com/thumbnail2.jpg", + "title": "광고 제목 4", + } + ] + } + """) + ), + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity getAllAdvertisements(); + + @Operation( + summary = "광고 상세 조회 API", + responses = { + @ApiResponse( + responseCode = "200", + content = @Content( + schema = @Schema(implementation = AdvGetDetailRes.class), + examples = @ExampleObject(value = """ + { + "images": [ + { + "imagesUrl": "http://example.com/image1.jpg", + "sequence": 1 + }, + { + "imagesUrl": "http://example.com/image2.jpg", + "sequence": 2 + } + ], + "title": "광고 제목", + "createAt": "2023.07.14", + "description": "광고 설명" + } + """) + ), + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "400", + description = "유효하지 않은 요청 파라미터 값입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + + @ApiResponse( + responseCode = "404", + description = "존재하지 않는 광고입니다.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity getAdvertisementsDetail( + @Parameter(required = true) final @PathVariable Long advId + ); +} diff --git a/dateroad-api/src/main/java/org/dateroad/advertisement/api/AdvertisementController.java b/dateroad-api/src/main/java/org/dateroad/advertisement/api/AdvertisementController.java index a7f9055f..e9f75511 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisement/api/AdvertisementController.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisement/api/AdvertisementController.java @@ -12,13 +12,13 @@ @RestController @RequiredArgsConstructor -@RequestMapping("/api/v1/advertisments") +@RequestMapping("/api/v1/advertisements") public class AdvertisementController { private final AdvertisementService advertisementService; @GetMapping public ResponseEntity getAllAdvertisements(){ - return ResponseEntity.ok(advertisementService.getAllAdvertisments()); + return ResponseEntity.ok(advertisementService.getAllAdvertisements()); } @GetMapping("{advId}") diff --git a/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetAllRes.java b/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetAllRes.java index 4f5806f1..e1b60e74 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetAllRes.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetAllRes.java @@ -8,24 +8,24 @@ @Builder(access = AccessLevel.PRIVATE) public record AdvGetAllRes( - List advertismentDtoResList + List advertisementDtoResList ) { - public static AdvGetAllRes of(List advertismentDtoResList) { + public static AdvGetAllRes of(List advertisementDtoResList) { return AdvGetAllRes.builder() - .advertismentDtoResList(advertismentDtoResList) + .advertisementDtoResList(advertisementDtoResList) .build(); } @Builder(access = AccessLevel.PRIVATE) - public record AdvertismentDtoRes( - Long advertismentId, + public record AdvertisementDtoRes( + Long advertisementId, String thumbnail, String title, AdTagType tag ) { - public static AdvertismentDtoRes of(Advertisement advertisement) { - return AdvertismentDtoRes.builder() - .advertismentId(advertisement.getId()) + public static AdvertisementDtoRes of(Advertisement advertisement) { + return AdvertisementDtoRes.builder() + .advertisementId(advertisement.getId()) .thumbnail(advertisement.getThumbnail()) .title(advertisement.getTitle()) .tag(advertisement.getTag()) diff --git a/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetDetailRes.java b/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetDetailRes.java index 74932102..99421e63 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetDetailRes.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisement/dto/response/AdvGetDetailRes.java @@ -1,5 +1,5 @@ package org.dateroad.advertisement.dto.response; - +import org.dateroad.advertisement.domain.AdTagType; import com.fasterxml.jackson.annotation.JsonFormat; import java.time.LocalDate; import java.util.List; @@ -12,14 +12,16 @@ public record AdvGetDetailRes( String title, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate createAt, - String description + String description, + AdTagType adTagType ) { - public static AdvGetDetailRes of(List images, String title, LocalDate createAt, String description) { + public static AdvGetDetailRes of(List images, String title, LocalDate createAt, String description, AdTagType type) { return AdvGetDetailRes.builder() .images(images) .title(title) .createAt(createAt) .description(description) + .adTagType(type) .build(); } diff --git a/dateroad-api/src/main/java/org/dateroad/advertisement/service/AdvertisementService.java b/dateroad-api/src/main/java/org/dateroad/advertisement/service/AdvertisementService.java index 5fa83fa5..bea4fb2f 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisement/service/AdvertisementService.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisement/service/AdvertisementService.java @@ -6,9 +6,9 @@ import org.dateroad.adImage.domain.AdImage; import org.dateroad.adImage.repository.AdImageRepository; import org.dateroad.advertisement.domain.Advertisement; -import org.dateroad.advertisement.repository.AdvertisementRepository; import org.dateroad.advertisement.dto.response.AdvGetAllRes; -import org.dateroad.advertisement.dto.response.AdvGetAllRes.AdvertismentDtoRes; +import org.dateroad.advertisement.repository.AdvertisementRepository; +import org.dateroad.advertisement.dto.response.AdvGetAllRes.AdvertisementDtoRes; import org.dateroad.advertisement.dto.response.AdvGetDetailRes; import org.dateroad.advertisement.dto.response.AdvGetDetailRes.AdvImagesRes; import org.dateroad.code.FailureCode; @@ -25,18 +25,12 @@ public class AdvertisementService { private final AdvertisementRepository advertisementRepository; private final AdImageRepository adImageRepository; - private static List getImages(final List adImages) { - return adImages.stream().map( - adImage -> AdvImagesRes.of(adImage.getImageUrl(), adImage.getSequence()) - ).toList(); - } - - public AdvGetAllRes getAllAdvertisments() { + public AdvGetAllRes getAllAdvertisements() { Pageable topFive = PageRequest.of(0, 5); - return AdvGetAllRes.of(advertisementRepository.findTop5ByOrderByCreatedDateDesc(topFive). - stream() - .map(AdvertismentDtoRes::of) - .collect(Collectors.toList())); + List advertisements = advertisementRepository.findTop5ByOrderByCreatedDateDesc(topFive); + List advertisementDtoResList = advertisements.stream() + .map(AdvertisementDtoRes::of).toList(); + return AdvGetAllRes.of(advertisementDtoResList); } public AdvGetDetailRes getAdvertisementsDetail(final Long advId) { @@ -44,7 +38,7 @@ public AdvGetDetailRes getAdvertisementsDetail(final Long advId) { List adImages = adImageRepository.findAllById(advId); return AdvGetDetailRes.of( getImages(adImages), advertisement.getTitle(), advertisement.getCreatedAt().toLocalDate(), - advertisement.getTitle() + advertisement.getTitle(), advertisement.getTag() ); } @@ -53,4 +47,10 @@ private Advertisement getAdvertisement(final Long advId) { () -> new EntityNotFoundException(FailureCode.ADVERTISEMENT_NOT_FOUND) ); } + + private List getImages(final List adImages) { + return adImages.stream().map( + adImage -> AdvImagesRes.of(adImage.getImageUrl(), adImage.getSequence()) + ).toList(); + } } diff --git a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java index 99b8f7db..4329a701 100644 --- a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java +++ b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java @@ -6,13 +6,9 @@ import org.dateroad.auth.jwt.refreshtoken.RefreshTokenGenerator; import org.dateroad.code.FailureCode; import org.dateroad.exception.UnauthorizedException; -import org.dateroad.refreshtoken.domain.RefreshToken; -import org.dateroad.refreshtoken.repository.RefreshTokenRepository; import org.springframework.stereotype.Component; import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.Base64; @RequiredArgsConstructor @Component diff --git a/dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java b/dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java index fd9c9e19..9d6e39af 100644 --- a/dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java +++ b/dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java @@ -1,10 +1,7 @@ package org.dateroad.config; -import java.util.concurrent.Executor; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration @EnableAsync diff --git a/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java b/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java index d3b47bba..a063fb44 100644 --- a/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java +++ b/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java @@ -8,9 +8,8 @@ import io.lettuce.core.protocol.CommandKeyword; import io.lettuce.core.protocol.CommandType; import lombok.RequiredArgsConstructor; -import org.dateroad.date.repository.CourseRepository; import org.dateroad.point.event.FreeEventListener; -import org.dateroad.point.event.pointEventListener; +import org.dateroad.point.event.PointEventListener; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -29,7 +28,7 @@ @Configuration @RequiredArgsConstructor public class RedisStreamConfig { - private final pointEventListener pointEventListener; + private final PointEventListener pointEventListener; private final FreeEventListener freeEventListener; @Value("${spring.data.redis.host}") private String host; @@ -51,9 +50,6 @@ public RedisConnectionFactory redisConnectionFactory() { } public void createStreamConsumerGroup(final String streamKey, final String consumerGroupName) { - // Stream이 존재 하지 않으면, MKSTREAM 옵션을 통해 만들고, ConsumerGroup또한 생성한다 - System.out.println(streamKey + consumerGroupName); - // Stream이 존재하지 않으면, MKSTREAM 옵션을 통해 스트림과 소비자 그룹을 생성 if (Boolean.FALSE.equals(redisTemplate().hasKey(streamKey))) { RedisAsyncCommands commands = (RedisAsyncCommands) Objects.requireNonNull( redisTemplate() @@ -94,7 +90,7 @@ public boolean isStreamConsumerGroupExist(final String streamKey, final String c } @Bean - public Subscription PointSubscription() { + public Subscription pointSubscription() { createStreamConsumerGroup("coursePoint", "courseGroup"); StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = StreamMessageListenerContainer.StreamMessageListenerContainerOptions .builder().pollTimeout(Duration.ofMillis(100)).build(); @@ -110,7 +106,7 @@ public Subscription PointSubscription() { } @Bean - public Subscription FreeSubscription() { + public Subscription freeSubscription() { createStreamConsumerGroup("courseFree", "courseGroup"); StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = StreamMessageListenerContainer.StreamMessageListenerContainerOptions .builder().pollTimeout(Duration.ofMillis(100)).build(); diff --git a/dateroad-api/src/main/java/org/dateroad/course/api/CourseApi.java b/dateroad-api/src/main/java/org/dateroad/course/api/CourseApi.java new file mode 100644 index 00000000..4af29d84 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/api/CourseApi.java @@ -0,0 +1,670 @@ +package org.dateroad.course.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import org.dateroad.auth.argumentresolve.UserId; +import org.dateroad.course.dto.request.CourseCreateReq; +import org.dateroad.course.dto.request.CourseCreateSwaggerDto; +import org.dateroad.course.dto.request.CourseGetAllReq; +import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.request.PointUseReq; +import org.dateroad.course.dto.request.TagCreateReq; +import org.dateroad.course.dto.response.CourseCreateRes; +import org.dateroad.course.dto.response.CourseGetAllRes; +import org.dateroad.course.dto.response.DateAccessGetAllRes; +import org.dateroad.date.dto.response.CourseGetDetailRes; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +@Tag(name = "코스 관련 API") +@SecurityRequirement(name = "Authorization") +public interface CourseApi { + @Operation( + summary = "코스 전체 조회 API", + parameters = { + @Parameter( + name = "country", + description = "데이트 코스 지역 대분류", + required = false, + schema = @Schema(type = "string", allowableValues = {"SEOUL", "GYEONGGI", "INCHEON"}), + example = "SEOUL" + ), + @Parameter( + name = "city", + description = "데이트 코스 지역 소분류", + required = false, + schema = @Schema(type = "string", allowableValues = { + "SEOUL_ENTIRE", "GANGNAM_SEOCHO", "JAMSIL_SONGPA_GANGDONG", + "KONDAE_SUNGSOO_WANGSIMNI", + "JONGNO_JUNGRO", "HONGDAE_HAPJEONG_MAPO", "YEONGDEUNGPO_YEOUIDO", + "YONGSAN_ITAEWON_HANNAM", + "YANGCHEON_GANGSEO", "SEONGBUK_NOWON_JUNGBANG", "GURO_GWANAK_DONGJAK", + "GYEONGGI_ENTIRE", + "SEONGNAM", "SUWON", "GOYANG_PAJU", "GIMPO", "YONGIN_HWASEONG", "ANYANG_GWACHEON", + "POCHEON_YANGJU", "NAMYANGJU_UIJEONGBU", "GWANGJU_ICHEON_YEOJU", + "GAPYEONG_YANGPYEONG", + "GUNPO_UIWANG", "HANAM_GURI", "SIHEUNG_GWANGMYEONG", "BUCHEON_ANSHAN", + "DONGDUCHEON_YEONCHEON", "PYEONGTAEK_OSAN_ANSEONG", "INCHEON_ENTIRE" + }), + example = "GANGNAM_SEOCHO" + ), + @Parameter( + name = "cost", + description = "필터링할 가격", + required = false, + schema = @Schema(type = "int"), + example = "50000" + ) + }, + responses = { + @ApiResponse( + responseCode = "200", + content = @Content( + schema = @Schema(implementation = CourseGetAllRes.class), + examples = @ExampleObject(value = """ + { + "courses": [ + { + "courseId": 1, + "thumbnail": "https://example.com/image1.jpg", + "city": "Seoul", + "title": "Introduction to Java", + "like": 100, + "cost": 500, + "duration": 10 + }, + { + "courseId": 2, + "thumbnail": "https://example.com/image2.jpg", + "city": "Busan", + "title": "Advanced Spring", + "like": 150, + "cost": 700, + "duration": 15 + } + ] + } + """) + ), + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity getAllCourses( + @Parameter(required = false) + final @ModelAttribute CourseGetAllReq courseGetAllReq + ); + + @Operation( + summary = "정렬된 코스 내역 조회 API", + parameters = { + @Parameter( + name = "sortBy", + description = "데이트 코스를 인기순/최신순 으로 조회하는 Api입니다.", + required = true, + schema = @Schema(type = "string", allowableValues = {"POPULAR", "LATEST"}), + example = "POPULAR" + ) + }, + responses = { + @ApiResponse( + responseCode = "200", + content = @Content( + schema = @Schema(implementation = CourseGetAllRes.class), + examples = @ExampleObject(value = """ + { + "courses": [ + { + "courseId":1, + "thumbnail": "www.asdfasdfds.jpg", + "title": "5년차 장기연애 커플이 보장하는 + 성수동 당일치기 데이트 코스", + "city": "건대/상수/왕십리", + "like" : 3, + "cost" : 10, + "duration" : 10 + }, + { + "courseId" : 2, + "thumbnail": "www.asdfasdfds.jpg", + "title": "5년차 장기연애 커플이 보장하는 + 성수동 당일치기 데이트 코스", + "city": "건대/상수/왕십리", + "like" : 3, + "cost" : 10, + "duration" : 10 + }, + { + "courseId":3, + "thumbnail": "www.asdfasdfds.jpg", + "title": "5년차 장기연애 커플이 보장하는 + 성수동 당일치기 데이트 코스", + "city": "건대/상수/왕십리", + "like" : 3, + "cost" : 10, + "duration" : 10 + } + } + """) + ), + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity getSortedCourses(final @RequestParam String sortBy); + + @Operation( + summary = "열람한 코스 내역 조회 API", + responses = { + @ApiResponse( + responseCode = "200", + content = @Content( + schema = @Schema(implementation = DateAccessGetAllRes.class), + examples = @ExampleObject(value = """ + { + "courses": [ + { + "courseId": 1, + "thumbnail": "https://example.com/image1.jpg", + "city": "Seoul", + "title": "Java Programming", + "like": 100, + "cost": 500, + "duration": 10.0 + }, + { + "courseId": 2, + "thumbnail": "https://example.com/image2.jpg", + "city": "Busan", + "title": "Spring Framework", + "like": 150, + "cost": 700, + "duration": 15.0 + } + ] + } + """) + ), + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity getAllDataAccessCourse( + @Parameter(hidden = true) final @UserId Long userId + ); + + @Operation( + summary = "코스 생성 API", + requestBody = @RequestBody( + content = @Content( + schema = @Schema(implementation = CourseCreateSwaggerDto.class), + examples = @ExampleObject(value = """ + { + "userId": 123, + "title": "Seoul Day Tour", + "description": "A day tour visiting main attractions in Seoul", + "city": "Seoul", + "country": "South Korea", + "date": "2024.07.14", + "startAt": "09:00", + "cost": 20000, + "places": [ + { + "sequence": 1, + "title": "Museum", + "duration": 1.5 + }, + { + "sequence": 2, + "title": "Park", + "duration": 2.0 + } + ], + "tags": [ + { + "tag": "여행" + }, + { + "tag": "드라이브" + } + ] + } + """) + ) + ), + responses = { + @ApiResponse( + responseCode = "201", + content = @Content( + schema = @Schema(implementation = CourseCreateRes.class), + examples = @ExampleObject(value = """ + { + "courseId": 1 + } + """) + ), + description = "코스가 성공적으로 생성되었습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity createCourse( + @Parameter(hidden = true) + @UserId final Long userId, + @RequestPart("course") final CourseCreateReq courseCreateReq, + @RequestPart("tags") final List tags, + @RequestPart("places") final List places, + @RequestPart("images") final List images + ); + + + @Operation( + summary = "내가 만든 코스 조회 API", + responses = { + @ApiResponse( + responseCode = "200", + content = @Content( + schema = @Schema(implementation = DateAccessGetAllRes.class), + examples = @ExampleObject(value = """ + { + "courses": [ + { + "courseId": 1, + "thumbnail": "https://example.com/image1.jpg", + "city": "Seoul", + "title": "Java Programming", + "like": 100, + "cost": 500, + "duration": 10.0 + }, + { + "courseId": 2, + "thumbnail": "https://example.com/image2.jpg", + "city": "Busan", + "title": "Spring Framework", + "like": 150, + "cost": 700, + "duration": 15.0 + } + ] + } + """) + ), + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity getMyCourses( + @Parameter(hidden = true) final @UserId Long userId + ); + + @Operation( + summary = "코스 열람하기 API", + description = "주어진 사용자 ID와 코스 ID를 기반으로 코스를 오픈합니다. 포인트가 없을시 정보를 보내지 않을시 무료열람에서 자동 차감됩니다.", + requestBody = @RequestBody( + description = "포인트 사용 요청 정보", + required = true, + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = PointUseReq.class), + examples = @ExampleObject(value = """ + { + "point": 100, + "type": "POINT_USED", + "description": "포인트획득" + }` + """) + ) + ), + responses = { + @ApiResponse( + responseCode = "200", + content = @Content, + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity openCourse( + @Parameter(hidden = true) + @UserId final Long userId, + @PathVariable final Long courseId, + @RequestBody final PointUseReq pointUseReq + ); + + @Operation( + summary = "코스 정보 조회 API", + responses = { + @ApiResponse( + responseCode = "200", + description = "코스 상세 정보입니다.", + content = @Content( + schema = @Schema(implementation = CourseGetDetailRes.class), + examples = @ExampleObject(value = """ + { + "courseId": 101, + "images": [ + { + "imageUrl": "https://example.com/image1.jpg", + "sequence": 1 + }, + { + "imageUrl": "https://example.com/image2.jpg", + "sequence": 2 + } + ], + "like": 120, + "totalTime": 3.5, + "date": "2024.07.14", + "city": "Seoul", + "title": "Seoul Day Tour", + "description": "A day tour visiting main attractions in Seoul", + "startAt": "09:00", + "places": [ + { + "sequence": 1, + "title": "Museum", + "duration": 1.5 + }, + { + "sequence": 2, + "title": "Park", + "duration": 2.0 + } + ], + "totalCost": 20000, + "tags": [ + { + "tag": "여행" + }, + { + "tag": "드라이브" + } + ], + "isAccess": true, + "free": 2, + "totalPoint": 150, + "isCourseMine": true, + "isUserLiked": false + } + """) + ) + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity getCourseDetail( + @Parameter(hidden = true) + @UserId Long userId, + @PathVariable("courseId") Long courseId + ); + + @Operation( + summary = "코스 좋아요 등록 API", + responses = { + @ApiResponse( + responseCode = "200", + description = "코스 좋아요 등록 API", + content = @Content), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity createCourseLike(@Parameter(hidden = true) + @UserId final Long userId, + @PathVariable final Long courseId); + + @Operation( + summary = "코스 좋아요 해제 API", + responses = { + @ApiResponse( + responseCode = "200", + description = "코스 좋아요 해제 API", + content = @Content), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity deleteCourseLike(@Parameter(hidden = true) + @UserId final Long userId, + @PathVariable final Long courseId); + + @Operation( + summary = "코스 삭제 API", + responses = { + @ApiResponse( + responseCode = "200", + description = "코스 삭제 API", + content = @Content), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + ResponseEntity deleteCourse(@Parameter(hidden = true) + @UserId Long userId, + @PathVariable final Long courseId); +} + diff --git a/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java b/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java index bc141d2b..4fc1f395 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java +++ b/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java @@ -12,7 +12,7 @@ import org.dateroad.course.dto.response.CourseCreateRes; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; -import org.dateroad.course.facade.AsyncService; +import org.dateroad.course.service.AsyncService; import org.dateroad.course.service.CourseService; import org.dateroad.date.domain.Course; import org.dateroad.date.dto.response.CourseGetDetailRes; @@ -26,7 +26,7 @@ @RestController @RequestMapping("/api/v1/courses") @RequiredArgsConstructor -public class CourseController { +public class CourseController implements CourseApi { private final CourseService courseService; private final AsyncService asyncService; @@ -45,8 +45,7 @@ public ResponseEntity getSortedCourses(final @RequestParam Stri } @GetMapping("/date-access") - public ResponseEntity getAllDataAccessCourse( - final @UserId Long userId + public ResponseEntity getAllDataAccessCourse(final @UserId Long userId ) { DateAccessGetAllRes dateAccessGetAllRes = courseService.getAllDataAccessCourse(userId); return ResponseEntity.ok(dateAccessGetAllRes); diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java index ef8b9fc9..c37d199a 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java @@ -1,6 +1,7 @@ package org.dateroad.course.dto.request; import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDate; import java.time.LocalTime; import lombok.AccessLevel; @@ -10,6 +11,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; +import org.dateroad.date.domain.Region; import org.springframework.format.annotation.DateTimeFormat; @Getter @@ -20,23 +22,25 @@ public class CourseCreateReq { private String title; @DateTimeFormat(pattern = "yyyy.MM.dd") + @Schema(description = "데이트 시작 날짜", example = "2024.07.04", pattern = "yyyy.MM.dd", type = "string") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") private LocalDate date; @DateTimeFormat(pattern = "HH:mm") + @Schema(description = "데이트 시작 시간", example = "12:30", pattern = "HH:mm", type = "string") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") private LocalTime startAt; - private String country; + private Region.MainRegion country; - private String city; + private Region.SubRegion city; private String description; private int cost; public static CourseCreateReq of(final String title,final LocalDate date,final LocalTime startAt, - final String country,final String city,final String description, + final Region.MainRegion country,final Region.SubRegion city,final String description, int cost) { return CourseCreateReq.builder() .title(title) diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateSwaggerDto.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateSwaggerDto.java new file mode 100644 index 00000000..91573d45 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateSwaggerDto.java @@ -0,0 +1,11 @@ +package org.dateroad.course.dto.request; + +import java.util.List; +import org.springframework.web.multipart.MultipartFile; + +public record CourseCreateSwaggerDto( + CourseCreateReq course, + List tags, + List places, + List images +) {} diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseGetAllReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseGetAllReq.java index a7a96f27..e9a8b674 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseGetAllReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseGetAllReq.java @@ -1,8 +1,10 @@ package org.dateroad.course.dto.request; +import org.dateroad.date.domain.Region; + public record CourseGetAllReq( - String country, - String city, + Region.MainRegion country, + Region.SubRegion city, Integer cost ) { } diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java index 5b29267c..213aa748 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java @@ -17,7 +17,7 @@ public class CoursePlaceGetReq { private float duration; private int sequence; - public static CoursePlaceGetReq of(String title, float duration, int sequence) { + public static CoursePlaceGetReq of(final String title, final float duration, final int sequence) { return CoursePlaceGetReq.builder() .title(title) .duration(duration) diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java index 2009a575..c88857da 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java @@ -19,7 +19,7 @@ public class PointUseReq { @Builder.Default private final String description = "포인트획득"; - public static PointUseReq of(int point, TransactionType type, String description) { + public static PointUseReq of(final int point, final TransactionType type, final String description) { return PointUseReq.builder() .point(point) .type(type) diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java index e994416d..80f76afc 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java @@ -17,7 +17,7 @@ public class TagCreateReq{ private DateTagType tag; - public static TagCreateReq of(DateTagType tag) { + public static TagCreateReq of(final DateTagType tag) { return TagCreateReq.builder() .tag(tag).build(); } diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java index cb8cf0ac..bfd3c07c 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java @@ -7,7 +7,7 @@ public record CourseCreateRes( Long courseId ) { - public static CourseCreateRes of(Long courseId) { + public static CourseCreateRes of(final Long courseId) { return CourseCreateRes.builder() .courseId(courseId) .build(); diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java index fe2a6cda..248efad5 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java @@ -2,6 +2,7 @@ import lombok.AccessLevel; import lombok.Builder; +import org.dateroad.date.domain.Course; @Builder(access = AccessLevel.PRIVATE) public record CourseDtoGetRes( @@ -13,20 +14,17 @@ public record CourseDtoGetRes( int cost, float duration ) { - public static CourseDtoGetRes of(Long courseId, + public static CourseDtoGetRes of(Course course, String thumbnail, - String city, - String title, int like, - int cost, float duration) { return CourseDtoGetRes.builder() - .courseId(courseId) + .courseId(course.getId()) .thumbnail(thumbnail) - .city(city) - .title(title) + .city(course.getCity().getDisplayName()) + .title(course.getTitle()) .like(like) - .cost(cost) + .cost(course.getCost()) .duration(duration) .build(); } diff --git a/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java b/dateroad-api/src/main/java/org/dateroad/course/service/AsyncService.java similarity index 91% rename from dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java rename to dateroad-api/src/main/java/org/dateroad/course/service/AsyncService.java index d5e875db..65e51133 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/AsyncService.java @@ -1,19 +1,16 @@ -package org.dateroad.course.facade; +package org.dateroad.course.service; import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import org.dateroad.Image.service.ImageService; +import org.dateroad.image.service.ImageService; import org.dateroad.course.dto.request.CoursePlaceGetReq; import org.dateroad.course.dto.request.PointUseReq; import org.dateroad.course.dto.request.TagCreateReq; -import org.dateroad.course.service.CoursePlaceService; -import org.dateroad.course.service.CourseTagService; import org.dateroad.date.domain.Course; import org.dateroad.image.domain.Image; -import org.dateroad.user.domain.User; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java index 3ae3ef79..acbef091 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java @@ -2,7 +2,6 @@ import java.util.List; import java.util.function.Function; -import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -14,7 +13,6 @@ import org.dateroad.course.dto.response.CourseDtoGetRes; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; -import org.dateroad.course.facade.AsyncService; import org.dateroad.date.domain.Course; import org.dateroad.date.dto.response.CourseGetDetailRes; import org.dateroad.date.repository.CourseRepository; @@ -106,7 +104,7 @@ private List convertToDtoList(final List entities, final return entities.stream() .map(converter) .map(this::convertToDto) - .collect(Collectors.toList()); + .toList(); } private CourseDtoGetRes convertToDto(final Course course) { @@ -115,12 +113,9 @@ private CourseDtoGetRes convertToDto(final Course course) { String thumbnailUrl = thumbnailImage != null ? thumbnailImage.getImageUrl() : null; float duration = asyncService.findTotalDurationByCourseId(course.getId()); return CourseDtoGetRes.of( - course.getId(), + course, thumbnailUrl, - course.getCity(), - course.getTitle(), likeCount, - course.getCost(), duration ); } @@ -210,26 +205,18 @@ private CoursePaymentType validateUserFreeOrPoint(final User user, final int req public void processCoursePayment(final CoursePaymentType coursePaymentType, final Long userId, final Point point, final PointUseReq pointUseReq) { - switch (coursePaymentType) { - case FREE -> { - asyncService.publishEventUserFree(userId); - } - case POINT -> { - pointRepository.save(point); - asyncService.publishEvenUserPoint(userId, pointUseReq); - } + if (coursePaymentType == CoursePaymentType.FREE) { + asyncService.publishEventUserFree(userId); + } + else if (coursePaymentType == CoursePaymentType.POINT) { + pointRepository.save(point); + asyncService.publishEvenUserPoint(userId, pointUseReq); } } public CourseGetDetailRes getCourseDetail(final Long userId, final Long courseId) { - - //course - courseId, title, date, start_at, description, totalCost, city, totalTime Course foundCourse = findCourseById(courseId); - - //user - userId, free, totalPoint, User foundUser = findUserById(userId); - - //나머지 - images, places, tags, isAccess, likes List foundImages = imageRepository.findAllByCourseId(foundCourse.getId()); validateImage(foundImages); @@ -270,22 +257,13 @@ public CourseGetDetailRes getCourseDetail(final Long userId, final Long courseId isUserLiked = likeRepository.existsByUserIdAndCourseId(foundUser.getId(), foundCourse.getId()); } - return CourseGetDetailRes.of( - foundCourse.getId(), + return CourseGetDetailRes.of(foundCourse, images, likesCount, - foundCourse.getTime(), - foundCourse.getDate(), - foundCourse.getCity(), - foundCourse.getTitle(), - foundCourse.getDescription(), - foundCourse.getStartAt(), places, - foundCourse.getCost(), tags, isAccess, - foundUser.getFree(), - foundUser.getTotalPoint(), + foundUser, isCourseMine, isUserLiked ); diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java index d3b625d8..ae65e1c3 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java @@ -1,7 +1,6 @@ package org.dateroad.course.service; import java.util.List; -import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.dateroad.course.dto.request.TagCreateReq; @@ -21,11 +20,8 @@ public class CourseTagService { @Transactional public void createCourseTags(final List tags, final Course course) { List coursePlaces = tags.stream() - .map(tag -> CourseTag.create( - course, - tag.getTag() - )) - .collect(Collectors.toList()); + .map(tag -> CourseTag.create(course, tag.getTag())) + .toList(); courseTagRepository.saveAllAndFlush(coursePlaces); } } \ No newline at end of file diff --git a/dateroad-api/src/main/java/org/dateroad/date/api/DateApi.java b/dateroad-api/src/main/java/org/dateroad/date/api/DateApi.java new file mode 100644 index 00000000..7ff458f8 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/api/DateApi.java @@ -0,0 +1,323 @@ +package org.dateroad.date.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.dateroad.auth.argumentresolve.UserId; +import org.dateroad.date.dto.request.DateCreateReq; +import org.dateroad.date.dto.response.DateDetailRes; +import org.dateroad.date.dto.response.DateGetNearestRes; +import org.dateroad.date.dto.response.DatesGetRes; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; + +public interface DateApi { + @Operation( + summary = "새로운 데이트 일정 생성", + description = "주어진 사용자 ID와 날짜 생성 요청 정보를 기반으로 새로운 날짜를 생성합니다.", + requestBody = @RequestBody( + description = "날짜 생성 요청 정보", + required = true, + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = DateCreateReq.class), + examples = @ExampleObject(value = """ + { + "title": "서울 여행", + "date": "2024.07.15", + "startAt": "09:00", + "tags": [ + { + "tag": "TRAVEL" + }, + { + "tag": "VACATION" + } + ], + "country": "대한민국", + "city": "서울", + "places": [ + { + "name": "경복궁", + "duration": 2.5, + "sequence": 1 + }, + { + "name": "남산타워", + "duration": 1.5, + "sequence": 2 + } + ] + } + """) + ) + ), + responses = { + @ApiResponse( + responseCode = "201", + description = "데이트가 성공적으로 생성되었습니다.", + content = @Content + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content + ), + @ApiResponse( + responseCode = "401", + description = "인증 오류", + content = @Content + ), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content + ) + } + ) + ResponseEntity createDate(@Parameter(hidden = true) + @UserId final Long userId, + @RequestBody final DateCreateReq dateCreateReq); + + @Operation( + summary = "지난 & 다가올 데이트 일정 전체 조회 API", + description = "지난 & 다가올 데이트 일정 전체 조회 API", + parameters = { + @Parameter( + name = "time", + description = "지난 데이트 vs 다가오는 데이트 구분 파라미터", + required = true, + schema = @Schema(type = "string", allowableValues = {"PAST", "FUTURE"}), + example = "PAST" + ) + }, + responses = { + @ApiResponse( + responseCode = "200", + description = "날짜 목록이 성공적으로 조회되었습니다.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = DatesGetRes.class), + examples = @ExampleObject(value = """ + { + "dates": [ + { + "dateId": 1, + "title": "서울 여행", + "date": "2024.07.15", + "city": "Seoul", + "tags": [ + { + "tag": "여행" + }, + { + "tag": "휴가" + } + ], + "dDay": 10 + }, + { + "dateId": 2, + "title": "부산 여행", + "date": "2024.08.20", + "city": "Busan", + "tags": [ + { + "tag": "여행" + }, + { + "tag": "바다" + } + ], + "dDay": 25 + } + ] + } + """) + ) + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content + ), + @ApiResponse( + responseCode = "401", + description = "인증 오류", + content = @Content + ), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content + ) + } + ) + ResponseEntity getDates(@Parameter(hidden = true) + @UserId final Long userId, + @RequestParam final String time); + + @Operation( + summary = "데이트 일정 상세 조회 API", + description = "데이트 일정 상세 조회 API.", + parameters = { + @Parameter( + name = "dateId", + description = "데이트 고유 ID", + required = true, + schema = @Schema(type = "long"), + example = "100" + ) + }, + responses = { + @ApiResponse( + responseCode = "200", + description = "데이트 상세 정보 조회 성공", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = DateDetailRes.class), + examples = @ExampleObject(value = """ + { + "dateId": 100, + "title": "서울 여행", + "startAt": "09:00", + "city": "Seoul", + "tags": [ + { + "tag": "여행" + }, + { + "tag": "휴가" + } + ], + "date": "2024.07.15", + "places": [ + { + "name": "경복궁", + "duration": 2.5, + "sequence": 1 + }, + { + "name": "남산타워", + "duration": 1.5, + "sequence": 2 + } + ], + "dDay": 10 + } + """) + ) + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content + ), + @ApiResponse( + responseCode = "401", + description = "인증 오류", + content = @Content + ), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content + ) + } + ) + ResponseEntity getDateDetail(@Parameter(hidden = true) + @UserId final Long userId, + @PathVariable final Long dateId); + + @Operation( + summary = "데이트 삭제 API", + description = "데이트 일정 삭제 API.", + parameters = { + @Parameter( + name = "dateId", + description = "데이트 고유 ID", + required = true, + schema = @Schema(type = "long"), + example = "100" + ) + }, + responses = { + @ApiResponse( + responseCode = "200", + description = "데이트 삭제 성공", + content = @Content), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content + ), + @ApiResponse( + responseCode = "401", + description = "인증 오류", + content = @Content + ), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content + ) + } + ) + ResponseEntity deleteDate(@Parameter(hidden = true) + @UserId final Long userId, + @PathVariable final Long dateId); + + + @Operation( + summary = "가장 가까운 날짜 정보 조회", + description = "가장 가까운 날짜 정보 조회", + responses = { + @ApiResponse( + responseCode = "200", + description = "가장 가까운 날짜 정보가 성공적으로 조회되었습니다.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = DateGetNearestRes.class), + examples = @ExampleObject(value = """ + { + "dateId": 1, + "dDay": 2, + "dateName": "마라톤 대회", + "month": 7, + "day": 15, + "startAt": "08:00 AM" + } + """) + ) + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content + ), + @ApiResponse( + responseCode = "401", + description = "인증 오류", + content = @Content + ), + @ApiResponse( + responseCode = "404", + description = "해당 데이트를 찾을 수 없습니다.", + content = @Content + ), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content + ) + } + ) + ResponseEntity getNearestDate(@Parameter(hidden = true) + @UserId final Long userId); + +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java b/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java index d9207ff2..5bb2db18 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java +++ b/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java @@ -14,7 +14,7 @@ @RequiredArgsConstructor @RequestMapping("/api/v1/dates") @RestController -public class DateController { +public class DateController implements DateApi{ private final DateService dateService; @PostMapping @@ -48,7 +48,6 @@ public ResponseEntity deleteDate(@UserId final Long userId, @GetMapping("/nearest") public ResponseEntity getNearestDate(@UserId final Long userId) { DateGetNearestRes dateGetNearestRes = dateService.getNearestDate(userId); - return ResponseEntity - .ok(dateGetNearestRes); + return ResponseEntity.ok(dateGetNearestRes); } } diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java index 57832b3f..513f88e7 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java @@ -5,6 +5,7 @@ import java.time.LocalDate; import java.time.LocalTime; import java.util.List; +import org.dateroad.date.domain.Region; public record DateCreateReq( String title, @@ -13,8 +14,8 @@ public record DateCreateReq( @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") LocalTime startAt, List tags, - String country, - String city, + Region.MainRegion country, + Region.SubRegion city, List places ) { } diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java index 4e35479d..cc7348e5 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java @@ -3,10 +3,8 @@ import lombok.AccessLevel; import lombok.Builder; import org.dateroad.date.domain.Course; -import org.dateroad.tag.domain.CourseTag; -import org.dateroad.tag.domain.DateTag; import org.dateroad.tag.domain.DateTagType; - +import org.dateroad.user.domain.User; import java.time.LocalDate; import java.time.LocalTime; import java.util.List; @@ -32,39 +30,31 @@ public record CourseGetDetailRes( boolean isUserLiked ) { - public static CourseGetDetailRes of(Long courseId, + public static CourseGetDetailRes of(Course course, List images, int like, - float totalTime, - LocalDate date, - String city, - String title, - String description, - LocalTime startAt, List places, - int totalCost, List tags, boolean isAccess, - int free, - int totalPoint, + User user, boolean isCourseMine, boolean isUserLiked) { return CourseGetDetailRes.builder() - .courseId(courseId) + .courseId(course.getId()) .images(images) .like(like) - .totalTime(totalTime) - .date(date) - .city(city) - .title(title) - .description(description) - .startAt(startAt) + .totalTime(course.getTime()) + .date(course.getDate()) + .city(course.getCity().getDisplayName()) + .title(course.getTitle()) + .description(course.getDescription()) + .startAt(course.getStartAt()) .places(places) - .totalCost(totalCost) + .totalCost(course.getCost()) .tags(tags) .isAccess(isAccess) - .free(free) - .totalPoint(totalPoint) + .free(user.getFree()) + .totalPoint(user.getTotalPoint()) .isCourseMine(isCourseMine) .isUserLiked(isUserLiked) .build(); diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java index 434d0734..5d70c312 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java @@ -4,6 +4,7 @@ import lombok.AccessLevel; import lombok.Builder; import org.dateroad.date.domain.Date; +import org.dateroad.date.domain.Region; import org.dateroad.place.domain.DatePlace; import org.dateroad.tag.domain.DateTag; @@ -17,7 +18,7 @@ public record DateDetailRes( String title, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") LocalTime startAt, - String city, + Region.SubRegion city, List tags, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate date, diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java index 07138a62..8c9fb628 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java @@ -3,9 +3,8 @@ import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AccessLevel; import lombok.Builder; +import org.dateroad.date.domain.Date; -import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.LocalTime; @Builder(access = AccessLevel.PRIVATE) @@ -18,20 +17,14 @@ public record DateGetNearestRes( @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "hh:mm a", timezone = "Asia/Seoul") LocalTime startAt ) { - public static DateGetNearestRes of(Long dateId, - int dDay, - String dateName, - int month, - int day, - LocalTime startAt) { + public static DateGetNearestRes of(Date date, int dDay) { return DateGetNearestRes.builder() - .dateId(dateId) + .dateId(date.getId()) .dDay(dDay) - .dateName(dateName) - .month(month) - .day(day) - .startAt(startAt) + .dateName(date.getTitle()) + .month(date.getDate().getMonthValue()) + .day(date.getDate().getDayOfMonth()) + .startAt(date.getStartAt()) .build(); } - } diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java index d76c49cf..26bdb1be 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java @@ -4,6 +4,7 @@ import lombok.AccessLevel; import lombok.Builder; import org.dateroad.date.domain.Date; +import org.dateroad.date.domain.Region; import org.dateroad.tag.domain.DateTag; import java.time.LocalDate; @@ -15,19 +16,17 @@ public record DateGetRes( String title, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate date, - String city, + Region.SubRegion city, List tags, int dDay ) { - public static DateGetRes of(Date date, List tags, int dDay) { + public static DateGetRes of(final Date date, final List tags, final int dDay) { return DateGetRes.builder() .dateId(date.getId()) .title(date.getTitle()) .date(date.getDate()) .city(date.getCity()) - .tags(tags.stream() - .map(TagGetRes::of) - .toList()) + .tags(tags.stream().map(TagGetRes::of).toList()) .dDay(dDay) .build(); } diff --git a/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java b/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java index de67c89d..f9f9a5d5 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java +++ b/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java @@ -8,7 +8,6 @@ import java.time.LocalDate; import java.util.List; -import java.time.LocalDate; import java.time.LocalTime; import java.util.Optional; diff --git a/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java b/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java index 656b54af..816237af 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java +++ b/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java @@ -48,8 +48,7 @@ public DatesGetRes getDates(final Long userId, final String time) { LocalDate currentDate = LocalDate.now(); List dates = fetchDatesByUserIdAndTime(userId, time, currentDate); List dateGetResList = dates.stream() - .map(date -> createDateGetRes(date, currentDate)) - .toList(); + .map(date -> createDateGetRes(date, currentDate)).toList(); return DatesGetRes.of(dateGetResList); } @@ -78,17 +77,9 @@ public DateGetNearestRes getNearestDate(final Long userId) { LocalDate currentDate = LocalDate.now(); LocalTime currentTime = LocalTime.now(); User findUser = getUser(userId); - Date nearest = findNearestDate(findUser.getId(), currentDate, currentTime); - int dDay = calculateDDay(nearest.getDate(), currentDate); - return DateGetNearestRes - .of( - nearest.getId(), - dDay, - nearest.getTitle(), - nearest.getDate().getMonthValue(), - nearest.getDate().getDayOfMonth(), - nearest.getStartAt() - ); + Date nearestDate = findNearestDate(findUser.getId(), currentDate, currentTime); + int dDay = calculateDDay(nearestDate.getDate(), currentDate); + return DateGetNearestRes.of(nearestDate, dDay); } private User getUser(Long userId) { @@ -171,7 +162,6 @@ private int calculateDDay(LocalDate eventDate, LocalDate currentDate) { } } - //가장 가까운 데이트 가져오기 private Date findNearestDate(Long userId, LocalDate currentDate, LocalTime currentTime) { return dateRepository.findFirstByUserIdAndDateAfterOrDateAndStartAtAfterOrderByDateAscStartAtAsc(userId, currentDate, currentDate, currentTime) .orElseThrow(() -> new EntityNotFoundException(FailureCode.DATE_NOT_FOUND)); diff --git a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java b/dateroad-api/src/main/java/org/dateroad/image/service/ImageService.java similarity index 79% rename from dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java rename to dateroad-api/src/main/java/org/dateroad/image/service/ImageService.java index 1ebd4c26..3de910ab 100644 --- a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java +++ b/dateroad-api/src/main/java/org/dateroad/image/service/ImageService.java @@ -1,4 +1,4 @@ -package org.dateroad.Image.service; +package org.dateroad.image.service; import java.io.IOException; import java.util.List; @@ -7,7 +7,8 @@ import lombok.RequiredArgsConstructor; import org.dateroad.code.FailureCode; import org.dateroad.date.domain.Course; -import org.dateroad.exception.DateRoadException; +import org.dateroad.exception.BadRequestException; +import org.dateroad.exception.EntityNotFoundException; import org.dateroad.image.domain.Image; import org.dateroad.image.repository.ImageRepository; import org.dateroad.s3.S3Service; @@ -29,7 +30,7 @@ public class ImageService { public List saveImages(final List images, final Course course) { AtomicInteger sequence = new AtomicInteger(); - List courseimages = images.stream() + List courseImages = images.stream() .map(img -> { try { return Image.create( @@ -38,17 +39,16 @@ public List saveImages(final List images, final Course cou sequence.getAndIncrement() ); } catch (IOException | ExecutionException | InterruptedException e) { - throw new RuntimeException(e); + throw new BadRequestException(FailureCode.BAD_REQUEST); } - }) - .toList(); - return imageRepository.saveAll(courseimages); + }).toList(); + return imageRepository.saveAll(courseImages); } public Image findFirstByCourseOrderBySequenceAsc(Course course) { return imageRepository.findFirstByCourseOrderBySequenceAsc(course) .orElseThrow( - () -> new DateRoadException(FailureCode.COURSE_THUMBNAIL_NOT_FOUND) + () -> new EntityNotFoundException(FailureCode.COURSE_THUMBNAIL_NOT_FOUND) ); } } diff --git a/dateroad-api/src/main/java/org/dateroad/point/api/PointApi.java b/dateroad-api/src/main/java/org/dateroad/point/api/PointApi.java new file mode 100644 index 00000000..de295669 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/point/api/PointApi.java @@ -0,0 +1,88 @@ +package org.dateroad.point.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.dateroad.auth.argumentresolve.UserId; +import org.dateroad.point.dto.response.PointGetAllRes; +import org.springframework.http.ResponseEntity; + +@Tag(name = "포인트 관련 API") +@SecurityRequirement(name = "Authorization") +public interface PointApi { + @Operation( + summary = "포인트 내역 조회 API", + responses = { + @ApiResponse( + responseCode = "200", + content = @Content( + schema = @Schema(implementation = PointGetAllRes.class), + examples = @ExampleObject(value = """ + { + "gained": { + "points": [ + { + "point": 100, + "description": "첫 구매 적립", + "createdAt": "2023.07.14" + }, + { + "point": 200, + "description": "리뷰 작성 적립", + "createdAt": "2023.07.15" + } + ] + }, + "used": { + "points": [ + { + "point": 50, + "description": "구매 사용", + "createdAt": "2023.07.16" + }, + { + "point": 80, + "description": "이벤트 참여 사용", + "createdAt": "2023.07.17" + } + ] + } + } + """) + ), + description = "요청이 성공했습니다." + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 형식이 올바르지 않습니다. Bearer 타입을 확인해 주세요.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰의 값이 올바르지 않습니다.", + content = @Content), + @ApiResponse( + responseCode = "401", + description = "액세스 토큰이 만료되었습니다. 재발급 받아주세요.", + content = @Content), + @ApiResponse( + responseCode = "405", + description = "잘못된 HTTP method 요청입니다.", + content = @Content), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류입니다.", + content = @Content)}) + public ResponseEntity getAllPoints( + @Parameter(hidden = true) + @UserId Long userId + ); +} diff --git a/dateroad-api/src/main/java/org/dateroad/point/api/PointController.java b/dateroad-api/src/main/java/org/dateroad/point/api/PointController.java index 121953a6..510df89c 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/api/PointController.java +++ b/dateroad-api/src/main/java/org/dateroad/point/api/PointController.java @@ -4,7 +4,6 @@ import org.dateroad.auth.argumentresolve.UserId; import org.dateroad.point.dto.response.PointGetAllRes; import org.dateroad.point.service.PointService; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -17,9 +16,7 @@ public class PointController { private final PointService pointService; @GetMapping - public ResponseEntity getAllPoints( - @UserId Long userId - ){ + public ResponseEntity getAllPoints(@UserId final Long userId){ PointGetAllRes pointGetAllRes = pointService.getAllPoints(userId); return ResponseEntity.ok(pointGetAllRes); } diff --git a/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java b/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java index 8966766a..8271bca8 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java +++ b/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java @@ -4,7 +4,7 @@ import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.dateroad.code.FailureCode; -import org.dateroad.exception.DateRoadException; +import org.dateroad.exception.EntityNotFoundException; import org.dateroad.user.domain.User; import org.dateroad.user.repository.UserRepository; import org.springframework.data.redis.connection.stream.MapRecord; @@ -30,7 +30,7 @@ public void onMessage(final MapRecord message) { private User getUser(Long userId) { return userRepository.findById(userId).orElseThrow( - () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + () -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND) ); } } diff --git a/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java b/dateroad-api/src/main/java/org/dateroad/point/event/PointEventListener.java similarity index 82% rename from dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java rename to dateroad-api/src/main/java/org/dateroad/point/event/PointEventListener.java index 478ef356..625cae63 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java +++ b/dateroad-api/src/main/java/org/dateroad/point/event/PointEventListener.java @@ -4,7 +4,8 @@ import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.dateroad.code.FailureCode; -import org.dateroad.exception.DateRoadException; +import org.dateroad.exception.EntityNotFoundException; +import org.dateroad.exception.UnauthorizedException; import org.dateroad.point.domain.TransactionType; import org.dateroad.user.domain.User; import org.dateroad.user.repository.UserRepository; @@ -15,7 +16,7 @@ @Component @RequiredArgsConstructor(access = AccessLevel.PROTECTED) -public class pointEventListener implements StreamListener> { +public class PointEventListener implements StreamListener> { private final UserRepository userRepository; @Override @@ -34,7 +35,7 @@ public void onMessage(final MapRecord message) { user.setTotalPoint(user.getTotalPoint() - point); break; default: - throw new IllegalArgumentException("잘못된 TransactionType: " + type); + throw new UnauthorizedException(FailureCode.INVALID_TRANSACTION_TYPE); } userRepository.save(user); } @@ -42,7 +43,7 @@ public void onMessage(final MapRecord message) { private User getUser(Long userId) { return userRepository.findById(userId).orElseThrow( - () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + () -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND) ); } } diff --git a/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java b/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java index ca29baf8..2e457a64 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java +++ b/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java @@ -14,19 +14,20 @@ @RequiredArgsConstructor public class PointService { private final PointRepository pointRepository; + public PointGetAllRes getAllPoints(Long userId) { List points = pointRepository.findAllByUserId(userId) .stream().map(PointDto::of) .toList(); - PointsDto gainedPoints = pointTypeChecktoList(points, TransactionType.POINT_GAINED); - PointsDto usedPoints = pointTypeChecktoList(points, TransactionType.POINT_USED); + PointsDto gainedPoints = pointTypeCheckToList(points, TransactionType.POINT_GAINED); + PointsDto usedPoints = pointTypeCheckToList(points, TransactionType.POINT_USED); return PointGetAllRes.of(gainedPoints,usedPoints); } - public PointsDto pointTypeChecktoList(List points, TransactionType type){ + + public PointsDto pointTypeCheckToList(List points, TransactionType type){ return PointsDto.of(points.stream() .filter(point -> point.transactionType() == type) .map(PointDtoRes::of) .toList()); } - } diff --git a/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java b/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java index f2a46ec2..bddf0bb5 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java +++ b/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java @@ -36,56 +36,44 @@ public ResponseEntity signUp(@RequestHeader(AUTHORIZATION) final @RequestPart("tag") List tag ) throws IOException { UserJwtInfoRes userSignUpRes = authService.signUp(token, userSignUPReq, image, tag); - return ResponseEntity - .status(HttpStatus.CREATED) - .body(userSignUpRes); + return ResponseEntity.status(HttpStatus.CREATED).body(userSignUpRes); } @PostMapping("/signin") public ResponseEntity signIn(@RequestHeader(AUTHORIZATION) final String token, @RequestBody final UserSignInReq userSignInReq) { UserJwtInfoRes userSignInRes = authService.signIn(token, userSignInReq); - return ResponseEntity - .ok(userSignInRes); + return ResponseEntity.status(HttpStatus.CREATED).body(userSignInRes); } @DeleteMapping("/signout") public ResponseEntity signout(@UserId final Long userId) { authService.signout(userId); - return ResponseEntity - .ok() - .build(); + return ResponseEntity.ok().build(); } @GetMapping("/check") public ResponseEntity checkNickname(@RequestParam("name") final String nickname) { authService.checkNickname(nickname); - return ResponseEntity - .ok() - .build(); + return ResponseEntity.ok().build(); } @DeleteMapping("/withdraw") public ResponseEntity withdraw(@UserId final Long userId, @RequestBody final AppleWithdrawAuthCodeReq appleWithdrawAuthCodeReq) { authService.withdraw(userId, appleWithdrawAuthCodeReq); - return ResponseEntity - .ok() - .build(); + return ResponseEntity.ok().build(); } @PatchMapping("/reissue") public ResponseEntity reissue(@RequestHeader(AUTHORIZATION) final String refreshToken) { UserJwtInfoRes userJwtInfoRes = authService.reissue(refreshToken); - return ResponseEntity - .ok(userJwtInfoRes); - + return ResponseEntity.ok(userJwtInfoRes); } @GetMapping("/main") public ResponseEntity getUserInfo(@UserId final Long userId) { UserInfoMainRes userInfoMainRes = userService.getUserInfoMain(userId); - return ResponseEntity - .ok(userInfoMainRes); + return ResponseEntity.ok(userInfoMainRes); } @GetMapping diff --git a/dateroad-api/src/main/java/org/dateroad/user/dto/request/UserSignUpReq.java b/dateroad-api/src/main/java/org/dateroad/user/dto/request/UserSignUpReq.java index a5546d69..c1664799 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/dto/request/UserSignUpReq.java +++ b/dateroad-api/src/main/java/org/dateroad/user/dto/request/UserSignUpReq.java @@ -1,10 +1,7 @@ package org.dateroad.user.dto.request; -import org.dateroad.tag.domain.DateTagType; import org.dateroad.user.domain.Platform; -import org.springframework.web.multipart.MultipartFile; -import java.util.List; public record UserSignUpReq( String name, diff --git a/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoGetMyPageRes.java b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoGetMyPageRes.java index 11795fd2..86af375f 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoGetMyPageRes.java +++ b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoGetMyPageRes.java @@ -2,7 +2,6 @@ import lombok.Builder; import org.dateroad.tag.domain.DateTagType; -import org.dateroad.tag.domain.UserTag; import java.util.List; diff --git a/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java b/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java index d2317af4..11f97558 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java +++ b/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java @@ -91,7 +91,7 @@ public void withdraw(final Long userId, final AppleWithdrawAuthCodeReq AppleWith } else if (foundUser.getPlatForm() == Platform.APPLE) { //애플 유저면 애플이랑 연결 끊기 appleFeignProvider.revokeUser(AppleWithdrawAuthCodeReq.authCode()); } else { - throw new BadRequestException(FailureCode.INVALID_PLATFORM_TYPE); + throw new InvalidValueException(FailureCode.INVALID_PLATFORM_TYPE); } deleteRefreshToken(foundUser.getId()); @@ -136,7 +136,7 @@ private User saveUser(final String name, final String image, final Platform plat } //유저 태그 생성 - public void saveUserTag(final User savedUser, final List userTags) { + private void saveUserTag(final User savedUser, final List userTags) { List userTageList = userTags.stream() .map(dateTagType -> UserTag.create(savedUser, dateTagType)) .map(userTagRepository::save) @@ -160,7 +160,7 @@ private User getUserByUserId(final long userId) { //태그 리스트 사이즈 검증 private void validateUserTagSize(final List userTags) { if (userTags.isEmpty() || userTags.size() > 3) { - throw new BadRequestException((FailureCode.WRONG_USER_TAG_SIZE)); + throw new InvalidValueException((FailureCode.WRONG_USER_TAG_SIZE)); } } diff --git a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java index a5b22254..06bdcb20 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -14,32 +14,34 @@ public enum FailureCode { BAD_REQUEST(HttpStatus.BAD_REQUEST, "e4000", "잘못된 요청입니다."), INVALID_PLATFORM_TYPE(HttpStatus.BAD_REQUEST, "e4001", "잘못된 플랫폼 타입입니다."), WRONG_USER_TAG_SIZE(HttpStatus.BAD_REQUEST, "e4002", "유저 태그 개수가 0이거나 3보다 많습니다.."), - WRONG_IMAGE_URL(HttpStatus.BAD_REQUEST, "e4003", "잘못된 이미지 URL 입니다."), + INVALID_IMAGE_TYPE(HttpStatus.BAD_REQUEST, "e4003", "지원하지 않는 이미지 확장자 입니다."), + INVALID_IMAGE_SIZE(HttpStatus.BAD_REQUEST, "e4004", "지원하지 않는 이미지 크기 입니다."), + WRONG_IMAGE_URL(HttpStatus.BAD_REQUEST, "e4005", "잘못된 이미지 URL 입니다."), /** * 401 Unauthorized */ UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "e4010", "리소스 접근 권한이 없습니다."), - INVALID_ACCESS_TOKEN_VALUE(HttpStatus.UNAUTHORIZED, "e4012", "액세스 토큰의 값이 올바르지 않습니다."), - EXPIRED_ACCESS_TOKEN(HttpStatus.UNAUTHORIZED, "e4013", "액세스 토큰이 만료되었습니다. 재발급 받아주세요."), - TOKEN_SUBJECT_NOT_NUMERIC_STRING(HttpStatus.UNAUTHORIZED, "e4014", "토큰의 subject가 숫자 문자열이 아닙니다."), + INVALID_ACCESS_TOKEN_VALUE(HttpStatus.UNAUTHORIZED, "e4011", "액세스 토큰의 값이 올바르지 않습니다."), + EXPIRED_ACCESS_TOKEN(HttpStatus.UNAUTHORIZED, "e4012", "액세스 토큰이 만료되었습니다. 재발급 받아주세요."), + TOKEN_SUBJECT_NOT_NUMERIC_STRING(HttpStatus.UNAUTHORIZED, "e4013", "토큰의 subject가 숫자 문자열이 아닙니다."), UNSUPPORTED_TOKEN_TYPE(HttpStatus.UNAUTHORIZED, "e4014", "잘못된 토큰 형식입니다."), MALFORMED_TOKEN(HttpStatus.UNAUTHORIZED, "e4015", "잘못된 토큰 구조입니다."), INVALID_SIGNATURE_TOKEN(HttpStatus.UNAUTHORIZED, "e4016", "잘못된 토큰 서명입니다."), KAKAO_INTERNER_ERROR(HttpStatus.UNAUTHORIZED, "e4017", "카카오 내부 서버 에러입니다."), INVALID_KAKAO_TOKEN(HttpStatus.UNAUTHORIZED, "e4018", "잘못된 카카오 액세스 토큰 형식입니다"), INVALID_APPLE_TOKEN_TYPE(HttpStatus.UNAUTHORIZED, "e4019", "Apple JWT 값의 alg, kid 정보가 올바르지 않습니다."), - INVALID_APPLE_IDENTITY_TOKEN(HttpStatus.UNAUTHORIZED, "e4020", "잘못된 애플 identity token입니다."), - UNABLE_MAKE_APPLE_PUBLIC_KEY(HttpStatus.UNAUTHORIZED, "e4021", "애플 퍼블릭키 생성에 문제가 생겼습니다."), - EXPIRED_APPLE_IDENTITY_TOKEN(HttpStatus.UNAUTHORIZED, "e4022", "애플 아이덴티티 토큰이 만료되었습니다."), - INVALID_APPLE_IDENTITY_TOKEN_CLAIMS(HttpStatus.UNAUTHORIZED, "e4023", "애플 아이덴티티 토큰의 클레임이 잘못되었습니다."), - - INVALID_REFRESH_TOKEN_VALUE(HttpStatus.UNAUTHORIZED, "e4024", "잘못된 리프레시토큰입니다."), - EXPIRED_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "e4025", "리프레시 토큰 기간이 만료되었습니다. 재로그인 해주세요"), - INVALID_KAKAO_ACCESS(HttpStatus.UNAUTHORIZED, "e4026", "잘못된 카카오 통신 접근입니다."), - UN_LINK_WITH_KAKAO_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "e4027", "카카오 연결 끊기 통신에 실패했습니다"), - INVALID_APPLE_TOKEN_ACCESS(HttpStatus.UNAUTHORIZED, "e4028", "잘못된 애플 토큰 통신 접근입니다."), - INVALID_DATE_GET_TYPE(HttpStatus.UNAUTHORIZED, "e4029", "잘못된 데이트 타입 검색입니다."), + INVALID_APPLE_IDENTITY_TOKEN(HttpStatus.UNAUTHORIZED, "e40110", "잘못된 애플 identity token입니다."), + UNABLE_MAKE_APPLE_PUBLIC_KEY(HttpStatus.UNAUTHORIZED, "e40111", "애플 퍼블릭키 생성에 문제가 생겼습니다."), + EXPIRED_APPLE_IDENTITY_TOKEN(HttpStatus.UNAUTHORIZED, "e40112", "애플 아이덴티티 토큰이 만료되었습니다."), + INVALID_APPLE_IDENTITY_TOKEN_CLAIMS(HttpStatus.UNAUTHORIZED, "e40113", "애플 아이덴티티 토큰의 클레임이 잘못되었습니다."), + INVALID_REFRESH_TOKEN_VALUE(HttpStatus.UNAUTHORIZED, "e40114", "잘못된 리프레시토큰입니다."), + EXPIRED_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "e40115", "리프레시 토큰 기간이 만료되었습니다. 재로그인 해주세요"), + INVALID_KAKAO_ACCESS(HttpStatus.UNAUTHORIZED, "e40116", "잘못된 카카오 통신 접근입니다."), + UN_LINK_WITH_KAKAO_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "e40117", "카카오 연결 끊기 통신에 실패했습니다"), + INVALID_APPLE_TOKEN_ACCESS(HttpStatus.UNAUTHORIZED, "e40118", "잘못된 애플 토큰 통신 접근입니다."), + INVALID_DATE_GET_TYPE(HttpStatus.UNAUTHORIZED, "e40119", "잘못된 데이트 타입 검색입니다."), + INVALID_TRANSACTION_TYPE(HttpStatus.UNAUTHORIZED, "e40120", "잘못된 포인트 거래 타입 검색입니다."), /** * 403 Forbidden @@ -63,11 +65,7 @@ public enum FailureCode { COURSE_TAG_NOT_FOUND(HttpStatus.NOT_FOUND, "e40410", "데이트 태그를 찾을 수 없습니다."), NEAREST_DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e40411", "다가오는 데이트를 찾을 수 없습니다."), LIKE_NOT_FOUND(HttpStatus.NOT_FOUND, "e40412", "해당 데이트 코스에 좋아요를 찾을 수 없습니다."), - - COURSE_DELETE_ACCESS_DENIED(HttpStatus.NOT_FOUND, "e40414", "해당 코스를 삭제할수 없습니다."), - - INSUFFICIENT_USER_POINTS(HttpStatus.NOT_FOUND, "e40413", "유저의 포인트가 부족합니다."), SORT_TYPE_NOT_FOUND(HttpStatus.UNAUTHORIZED, "e40414", "해당 순서 타입을 찾을 수 없습니다."), ADVERTISEMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "e40415", "해당 광고를 찾을 수 없습니다."), @@ -85,13 +83,10 @@ public enum FailureCode { DUPLICATE_NICKNAME(HttpStatus.CONFLICT, "e4092", "이미 존재하는 닉네임입니다."), DUPLICATE_COURSE_LIKE(HttpStatus.CONFLICT, "e4093", "해당 데이트 코스에 좋아요가 이미 존재합니다."), - INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "e5000", "서버 내부 오류입니다."); - - /** * 500 Internal Server Error */ - + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "e5000", "서버 내부 오류입니다."); private final HttpStatus httpStatus; private final String code; diff --git a/dateroad-domain/src/main/java/org/dateroad/adImage/domain/AdImage.java b/dateroad-domain/src/main/java/org/dateroad/adImage/domain/AdImage.java index d8eaa45c..05fce39e 100644 --- a/dateroad-domain/src/main/java/org/dateroad/adImage/domain/AdImage.java +++ b/dateroad-domain/src/main/java/org/dateroad/adImage/domain/AdImage.java @@ -31,7 +31,7 @@ public class AdImage extends BaseTimeEntity { private Long id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "advertisment_id") + @JoinColumn(name = "advertisement_id") @NotNull private Advertisement advertisement; diff --git a/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java b/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java index f0b5f091..62b61a8b 100644 --- a/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java @@ -7,5 +7,5 @@ @Repository public interface AdImageRepository extends JpaRepository { - List findAllById(Long advertismentId); + List findAllById(Long advertisementId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/advertisement/repository/AdvertisementRepository.java b/dateroad-domain/src/main/java/org/dateroad/advertisement/repository/AdvertisementRepository.java index 8267ee94..3dc154cc 100644 --- a/dateroad-domain/src/main/java/org/dateroad/advertisement/repository/AdvertisementRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/advertisement/repository/AdvertisementRepository.java @@ -1,6 +1,7 @@ package org.dateroad.advertisement.repository; import java.util.List; + import org.dateroad.advertisement.domain.Advertisement; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,6 +10,6 @@ @Repository public interface AdvertisementRepository extends JpaRepository { - @Query("SELECT a FROM Advertisement a ORDER BY a.createdAt DESC") + @Query("SELECT a FROM advertisements a ORDER BY a.createdAt DESC") List findTop5ByOrderByCreatedDateDesc(Pageable pageable); } diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java index baa1e452..31341e8e 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java @@ -9,7 +9,6 @@ import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.LocalTime; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -50,7 +49,7 @@ public class Course extends DateBase { private String thumbnail; public static Course create(final User user, final String title, final String description, - final String country, final String city, + final Region.MainRegion country, final Region.SubRegion city, final int cost, final LocalDate date, final LocalTime startAt, final float time) { return Course.builder() diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java index 42360067..316760ef 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java @@ -29,7 +29,7 @@ public class Date extends DateBase { public static Date create(final User user, final String title, final LocalDate date, final LocalTime startAt, - final String country, final String city) { + final Region.MainRegion country, final Region.SubRegion city) { return Date.builder() .user(user) .title(title) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java index fbb0b3ec..56dea392 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java @@ -1,6 +1,8 @@ package org.dateroad.date.domain; import jakarta.persistence.Column; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; @@ -41,9 +43,11 @@ public abstract class DateBase extends BaseTimeEntity { @Column(name = "country") @NotNull - private String country; + @Enumerated(EnumType.STRING) + private Region.MainRegion country; @Column(name = "city") @NotNull - private String city; + @Enumerated(EnumType.STRING) + private Region.SubRegion city; } diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Region.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Region.java new file mode 100644 index 00000000..0894b925 --- /dev/null +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Region.java @@ -0,0 +1,62 @@ +package org.dateroad.date.domain; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public class Region { + + @Getter + public enum MainRegion { + SEOUL, + GYEONGGI, + INCHEON + } + + @Getter + public enum SubRegion { + // 서울 소분류 + SEOUL_ENTIRE("서울 전체", MainRegion.SEOUL), + GANGNAM_SEOCHO("강남/서초", MainRegion.SEOUL), + JAMSIL_SONGPA_GANGDONG("잠실/송파/강동", MainRegion.SEOUL), + KONDAE_SUNGSOO_WANGSIMNI("건대/성수/왕십리", MainRegion.SEOUL), + JONGNO_JUNGRO("종로/중구", MainRegion.SEOUL), + HONGDAE_HAPJEONG_MAPO("홍대/합정/마포", MainRegion.SEOUL), + YEONGDEUNGPO_YEOUIDO("영등포/여의도", MainRegion.SEOUL), + YONGSAN_ITAEWON_HANNAM("용산/이태원/한남", MainRegion.SEOUL), + YANGCHEON_GANGSEO("양천/강서", MainRegion.SEOUL), + SEONGBUK_NOWON_JUNGBANG("성북/노원/중랑", MainRegion.SEOUL), + GURO_GWANAK_DONGJAK("구로/관악/동작", MainRegion.SEOUL), + + // 경기 소분류 + GYEONGGI_ENTIRE("경기 전체", MainRegion.GYEONGGI), + SEONGNAM("성남", MainRegion.GYEONGGI), + SUWON("수원", MainRegion.GYEONGGI), + GOYANG_PAJU("고양/파주", MainRegion.GYEONGGI), + GIMPO("김포", MainRegion.GYEONGGI), + YONGIN_HWASEONG("용인/화성", MainRegion.GYEONGGI), + ANYANG_GWACHEON("안양/과천", MainRegion.GYEONGGI), + POCHEON_YANGJU("포천/양주", MainRegion.GYEONGGI), + NAMYANGJU_UIJEONGBU("남양주/의정부", MainRegion.GYEONGGI), + GWANGJU_ICHEON_YEOJU("광주/이천/여주", MainRegion.GYEONGGI), + GAPYEONG_YANGPYEONG("가평/양평", MainRegion.GYEONGGI), + GUNPO_UIWANG("군포/의왕", MainRegion.GYEONGGI), + HANAM_GURI("하남/구리", MainRegion.GYEONGGI), + SIHEUNG_GWANGMYEONG("시흥/광명", MainRegion.GYEONGGI), + BUCHEON_ANSHAN("부천/안산", MainRegion.GYEONGGI), + DONGDUCHEON_YEONCHEON("동두천/연천", MainRegion.GYEONGGI), + PYEONGTAEK_OSAN_ANSEONG("평택/오산/안성", MainRegion.GYEONGGI), + + // 인천 소분류 + INCHEON_ENTIRE("인천 전체", MainRegion.INCHEON); + + private final String displayName; + private final MainRegion mainRegion; + + SubRegion(String displayName, MainRegion mainRegion) { + this.displayName = displayName; + this.mainRegion = mainRegion; + } + } +} diff --git a/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java b/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java index 15602e50..8d7af21a 100644 --- a/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java +++ b/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java @@ -13,7 +13,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.ToString; import lombok.experimental.SuperBuilder; import org.dateroad.common.BaseTimeEntity; import org.dateroad.date.domain.Course; diff --git a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java index 2ec28d65..e8c89bb8 100644 --- a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java @@ -1,7 +1,6 @@ package org.dateroad.place.repository; import java.util.List; -import org.dateroad.date.domain.Course; import org.dateroad.place.domain.CoursePlace; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; diff --git a/dateroad-domain/src/main/java/org/dateroad/point/repository/PointRepository.java b/dateroad-domain/src/main/java/org/dateroad/point/repository/PointRepository.java index 03b96bbc..467d87ef 100644 --- a/dateroad-domain/src/main/java/org/dateroad/point/repository/PointRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/point/repository/PointRepository.java @@ -1,7 +1,6 @@ package org.dateroad.point.repository; import java.util.List; -import org.dateroad.like.domain.Like; import org.dateroad.point.domain.Point; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java b/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java index e7f7e8f5..ec349602 100644 --- a/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java +++ b/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java @@ -3,8 +3,6 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import lombok.*; -import org.springframework.boot.autoconfigure.data.redis.RedisProperties; -import org.springframework.cglib.core.Local; import java.time.LocalDateTime; diff --git a/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTagType.java b/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTagType.java index fcd4825b..bb314eb3 100644 --- a/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTagType.java +++ b/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTagType.java @@ -1,7 +1,21 @@ package org.dateroad.tag.domain; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public enum DateTagType { - // TODO,~! -> date tag 작성 - TODO, - TEST, + DRIVE("드라이브"), + SHOPPING("쇼핑"), + INDOORS("실내"), + HEALING("힐링"), + ALCOHOL("알콜"), + FOOD("식도락"), + WORKSHOP("공방"), + NATURE("자연"), + ACTIVITY("액티비티"), + PERFORMANCE_MUSIC("공연·음악"), + EXHIBITION_POPUP("전시·팝업"); + private final String description; } + diff --git a/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java b/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java index 20ac7830..d6d61c6f 100644 --- a/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java @@ -1,9 +1,7 @@ package org.dateroad.tag.repository; -import org.dateroad.tag.domain.DateTagType; import org.dateroad.tag.domain.UserTag; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import java.util.List; diff --git a/dateroad-domain/src/main/java/org/dateroad/user/domain/Platform.java b/dateroad-domain/src/main/java/org/dateroad/user/domain/Platform.java index 79bbb782..12cda002 100644 --- a/dateroad-domain/src/main/java/org/dateroad/user/domain/Platform.java +++ b/dateroad-domain/src/main/java/org/dateroad/user/domain/Platform.java @@ -2,10 +2,7 @@ import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import org.dateroad.code.FailureCode; -import org.dateroad.exception.InvalidValueException; -import java.util.Arrays; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public enum Platform { diff --git a/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java b/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java index 3b244265..ff63f57e 100644 --- a/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java +++ b/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java @@ -11,7 +11,6 @@ import org.dateroad.common.BaseTimeEntity; import org.dateroad.tag.domain.UserTag; -import java.util.HashSet; import java.util.Set; diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java index 374ab369..e77874cf 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java @@ -1,6 +1,5 @@ package org.dateroad.feign.apple; -import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java index d719510a..34c2cb3a 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java @@ -2,7 +2,6 @@ import io.jsonwebtoken.Claims; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/ApplePublicKeys.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/ApplePublicKeys.java index ba56e53c..b642cef6 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/ApplePublicKeys.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/ApplePublicKeys.java @@ -1,12 +1,10 @@ package org.dateroad.feign.apple; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import org.dateroad.code.FailureCode; import org.dateroad.exception.UnauthorizedException; -import org.springframework.stereotype.Component; import java.util.List; diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java index be7869a1..cd772e5a 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java @@ -7,8 +7,7 @@ @Getter public enum KakaoHeaderType { BEARER("Bearer "), - KAKAOAK("KakaoAK "), - ; + KAKAOAK("KakaoAK "); private final String tokenType; } diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoErrorRes.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoErrorRes.java index f309fdeb..79070c47 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoErrorRes.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoErrorRes.java @@ -1,7 +1,5 @@ package org.dateroad.feign.kakao.dto.response; -import lombok.Getter; - public record KakaoErrorRes( String msg, int code diff --git a/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java b/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java index 410d59c0..51c87f7a 100644 --- a/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java +++ b/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java @@ -2,13 +2,12 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; - import org.dateroad.code.FailureCode; +import org.dateroad.exception.InvalidValueException; import org.dateroad.exception.BadRequestException; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; -import org.springframework.util.concurrent.ListenableFuture; import org.springframework.web.multipart.MultipartFile; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; @@ -25,7 +24,7 @@ public class S3Service { private final String bucketName; private final AWSConfig awsConfig; private static final List IMAGE_EXTENSIONS = Arrays.asList("image/jpeg", "image/png", "image/jpg", "image/webp"); - + private static final Long MAX_FILE_SIZE = 5 * 1024 * 1024L; public S3Service(@Value("${aws-property.s3-bucket-name}") final String bucketName, AWSConfig awsConfig) { this.bucketName = bucketName; @@ -70,15 +69,13 @@ private String generateImageFileName() { private void validateExtension(MultipartFile image) { String contentType = image.getContentType(); if (!IMAGE_EXTENSIONS.contains(contentType)) { - throw new RuntimeException("이미지 확장자는 jpg, png, webp만 가능합니다."); + throw new InvalidValueException(FailureCode.INVALID_IMAGE_TYPE); } } - private static final Long MAX_FILE_SIZE = 5 * 1024 * 1024L; - private void validateFileSize(MultipartFile image) { if (image.getSize() > MAX_FILE_SIZE) { - throw new RuntimeException("이미지 사이즈는 5MB를 넘을 수 없습니다."); + throw new InvalidValueException(FailureCode.INVALID_IMAGE_SIZE); } }