diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceAutoCompleteUrlRequest.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceAutoCompleteUrlRequest.kt index fed5218c..c4ad6077 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceAutoCompleteUrlRequest.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceAutoCompleteUrlRequest.kt @@ -1,10 +1,26 @@ package com.piikii.application.port.input.dto.request +import com.piikii.common.exception.ExceptionCode +import com.piikii.common.exception.PiikiiException import io.swagger.v3.oas.annotations.media.Schema -import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.NotBlank +import java.net.URI data class PlaceAutoCompleteUrlRequest( - @field:NotNull(message = "URL 입력은 필수 입니다.") + @field:NotBlank(message = "URL 입력은 필수 입니다.") @field:Schema(description = "장소 자동완성을 위한 지도 URL", example = "https://test.com/1231421") - val url: String, -) + var url: String, +) { + init { + val validatedUrl = + Regex(REGEX_PATTERN).find(url)?.value ?: throw PiikiiException( + exceptionCode = ExceptionCode.ILLEGAL_ARGUMENT_EXCEPTION, + detailMessage = "URL이 요청 형식에 맞지 않습니다. : $url", + ) + url = URI(validatedUrl).toString() + } + + companion object { + private const val REGEX_PATTERN = "(https://\\S+)" + } +} diff --git a/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceAutoCompleteAdapter.kt b/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceAutoCompleteAdapter.kt index 22d2e55a..b4eb8c1e 100644 --- a/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceAutoCompleteAdapter.kt +++ b/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceAutoCompleteAdapter.kt @@ -5,22 +5,22 @@ import com.piikii.application.domain.place.OriginPlace import com.piikii.application.port.output.web.OriginPlaceAutoCompletePort import com.piikii.common.exception.ExceptionCode import com.piikii.common.exception.PiikiiException -import com.piikii.output.web.lemon.parser.LemonOriginMapIdParser +import com.piikii.output.web.lemon.parser.LemonOriginMapIdParserStrategy import org.springframework.stereotype.Component import org.springframework.web.client.RestClient import org.springframework.web.client.body @Component class LemonPlaceAutoCompleteAdapter( - private val lemonOriginMapIdParser: LemonOriginMapIdParser, + private val lemonOriginMapIdParserStrategy: LemonOriginMapIdParserStrategy, private val lemonApiClient: RestClient, ) : OriginPlaceAutoCompletePort { override fun isAutoCompleteSupportedUrl(url: String): Boolean { - return lemonOriginMapIdParser.isAutoCompleteSupportedUrl(url) + return lemonOriginMapIdParserStrategy.getParserBySupportedUrl(url) != null } override fun extractOriginMapId(url: String): OriginMapId { - return lemonOriginMapIdParser.parseOriginMapId(url) + return lemonOriginMapIdParserStrategy.getParserBySupportedUrl(url)?.parseOriginMapId(url) ?: throw PiikiiException(ExceptionCode.NOT_SUPPORT_AUTO_COMPLETE_URL) } diff --git a/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceInfoResponse.kt b/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceInfoResponse.kt index 6c720a18..07e0d646 100644 --- a/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceInfoResponse.kt +++ b/piikii-output-web/lemon/src/main/kotlin/com/piikii/output/web/lemon/adapter/LemonPlaceInfoResponse.kt @@ -10,15 +10,16 @@ import com.piikii.application.domain.place.OriginPlace @JsonIgnoreProperties(ignoreUnknown = true) data class LemonPlaceInfoResponse( - val isMapUser: String?, - val isExist: Boolean?, - val basicInfo: BasicInfo, + @JsonProperty("ismapuser") val isMapUser: String?, + @JsonProperty("isexist") val isExist: Boolean?, + @JsonProperty("basicinfo") val basicInfo: BasicInfo?, val comment: Comment?, - val menuInfo: MenuInfo, - val photo: Photo, + @JsonProperty("menuinfo") val menuInfo: MenuInfo?, + val photo: Photo?, ) { fun toOriginPlace(url: String): OriginPlace { - val fullAddress = "${basicInfo.address.region.newaddrfullname} ${basicInfo.address.newaddr.newaddrfull}".trim() + requireNotNull(basicInfo) { "BasicInfo is required" } + val fullAddress = "${basicInfo.address.region.newAddrFullName} ${basicInfo.address.newAddr.newAddrFull}".trim() return OriginPlace( id = LongTypeId(0L), name = basicInfo.name, @@ -40,83 +41,70 @@ data class LemonPlaceInfoResponse( @JsonIgnoreProperties(ignoreUnknown = true) data class BasicInfo( val cid: Long, - @JsonProperty("placenamefull") - val name: String, - @JsonProperty("mainphotourl") - val mainPhotoUrl: String, - @JsonProperty("phonenum") - val phoneNumber: String?, + @JsonProperty("placenamefull") val name: String, + @JsonProperty("mainphotourl") val mainPhotoUrl: String, + @JsonProperty("phonenum") val phoneNumber: String?, val address: Address, val homepage: String?, val category: Category, val feedback: Feedback, - val openHour: OpenHour, + @JsonProperty("openhour") val openHour: OpenHour, val tags: List?, - @JsonProperty("x") - val longitude: Double?, - @JsonProperty("y") - val latitude: Double?, + @JsonProperty("x") val longitude: Double?, + @JsonProperty("y") val latitude: Double?, ) @JsonIgnoreProperties(ignoreUnknown = true) data class Address( - val newaddr: NewAddress, + @JsonProperty("newaddr") val newAddr: NewAddress, val region: Region, - val addrbunho: String? = null, + @JsonProperty("addrbunho") val addrBunho: String?, ) @JsonIgnoreProperties(ignoreUnknown = true) data class NewAddress( - val newaddrfull: String, - val bsizonno: String, + @JsonProperty("newaddrfull") val newAddrFull: String, + @JsonProperty("bsizonno") val bsiZonNo: String, ) @JsonIgnoreProperties(ignoreUnknown = true) data class Region( val name3: String, - val fullname: String, - val newaddrfullname: String, + @JsonProperty("fullname") val fullName: String, + @JsonProperty("newaddrfullname") val newAddrFullName: String, ) @JsonIgnoreProperties(ignoreUnknown = true) data class Category( - @JsonProperty("catename") - val firstCategoryName: String, - @JsonProperty("cate1name") - val secondCategoryName: String, + @JsonProperty("catename") val firstCategoryName: String, + @JsonProperty("cate1name") val secondCategoryName: String, ) @JsonIgnoreProperties(ignoreUnknown = true) data class Feedback( - @JsonProperty("scoresum") - val sumOfScore: Int, - @JsonProperty("scorecnt") - val countOfScore: Int, - @JsonProperty("blogrvwcnt") - val countOfBlogReview: Int, - @JsonProperty("comntcnt") - val countOfReviewComment: Int, - @JsonProperty("allphotocnt") - val countOfAllPhoto: Int, - @JsonProperty("reviewphotocnt") - val countOfPhotoReview: Int, + @JsonProperty("scoresum") val sumOfScore: Int = 0, + @JsonProperty("scorecnt") val countOfScore: Int = 0, + @JsonProperty("blogrvwcnt") val countOfBlogReview: Int = 0, + @JsonProperty("comntcnt") val countOfReviewComment: Int = 0, + @JsonProperty("allphotocnt") val countOfAllPhoto: Int = 0, + @JsonProperty("reviewphotocnt") val countOfPhotoReview: Int = 0, ) { fun calculateStarGrade(): Double? = if (countOfScore > 0) sumOfScore.toDouble() / countOfScore else null } @JsonIgnoreProperties(ignoreUnknown = true) data class OpenHour( - val periodList: List?, - val offdayList: List?, + @JsonProperty("periodlist") val periodList: List?, + @JsonProperty("offdaylist") val offDayList: List?, ) { fun toPrintFormat(): String? { - val openingHour = - periodList?.first { it.periodName == OPEN_HOUR_PERIOD_NAME } - ?.toPrintFormat() - val offdaySchedule = - offdayList?.map { it.toPrintFormat() } - ?.joinToString { JOINER } - return if (openingHour == null && offdaySchedule == null) null else "$openingHour$JOINER$offdaySchedule" + val openingHour = periodList?.firstOrNull { it.periodName == OPEN_HOUR_PERIOD_NAME }?.toPrintFormat() + val offDaySchedule = offDayList?.mapNotNull { it.toPrintFormat() }?.joinToString(JOINER) + return if (openingHour == null && offDaySchedule.isNullOrEmpty()) { + null + } else { + "$openingHour$JOINER$offDaySchedule".trim() + } } companion object { @@ -127,37 +115,41 @@ data class LemonPlaceInfoResponse( @JsonIgnoreProperties(ignoreUnknown = true) data class Period( - val periodName: String, - val timeList: List