Skip to content

Commit

Permalink
feat: #52 파일 업로드 기능 별도의 API로 분리, API 요청 시 이미지 파일 첨부 방식 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
Wo-ogie committed Nov 10, 2024
1 parent b85698c commit ae8f741
Show file tree
Hide file tree
Showing 63 changed files with 1,076 additions and 384 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.damaba.common_file.domain

data class DeleteFileEvent(val urls: List<String>) {
constructor(url: String) : this(listOf(url))
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.damaba.common_file.domain

data class UploadedFile(
data class File(
val name: String,
val url: String,
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.damaba.common_file.domain

data class FileUploadRollbackEvent(val uploadedFiles: List<UploadedFile>) {
constructor(uploadedFile: UploadedFile) : this(listOf(uploadedFile))
data class FileUploadRollbackEvent(val uploadedFiles: List<File>) {
constructor(uploadedFile: File) : this(listOf(uploadedFile))
}
5 changes: 1 addition & 4 deletions damaba/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
* Main Server Dependencies
*/
implementation(project(":user"))
implementation(project(":file"))
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-aop")

Expand Down Expand Up @@ -55,10 +56,6 @@ dependencies {
implementation("com.h2database:h2")
implementation("com.mysql:mysql-connector-j")

// AWS S3
implementation(platform("software.amazon.awssdk:bom:2.27.21"))
implementation("software.amazon.awssdk:s3")

/**
* Common
*/
Expand Down
6 changes: 3 additions & 3 deletions damaba/src/main/kotlin/com/damaba/damaba/DamabaApplication.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.damaba.damaba

import com.damaba.damaba.property.AwsProperties
import com.damaba.damaba.property.ThreadPoolProperties
import com.damaba.user.property.AuthProperties
import org.springframework.boot.autoconfigure.SpringBootApplication
Expand All @@ -14,17 +13,18 @@ import org.springframework.context.annotation.PropertySource
scanBasePackages = [
"com.damaba.common_logging",
"com.damaba.common_exception",
"com.damaba.file",
"com.damaba.damaba",
"com.damaba.user",
],
)
@PropertySource("classpath:env.properties")
@EnableConfigurationProperties(
com.damaba.user.property.DamabaProperties::class,
com.damaba.file.property.DamabaProperties::class,
com.damaba.damaba.property.DamabaProperties::class,
AuthProperties::class,
ThreadPoolProperties::class,
AwsProperties::class,
com.damaba.file.property.AwsProperties::class,
)
@EntityScan(basePackages = ["com.damaba.user", "com.damaba.damaba"])
@EnableFeignClients(basePackages = ["com.damaba.user"])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.damaba.damaba.adapter.inbound.common.dto

import com.damaba.damaba.domain.common.Address
import io.swagger.v3.oas.annotations.media.Schema

data class AddressRequest(
@Schema(description = "시/도 이름", example = "경기")
val sido: String,

@Schema(description = "시/군/구 이름", example = "성남시 분당구")
val sigungu: String,

@Schema(description = "도로명 주소", example = "경기 성남시 분당구 판교역로 166")
val roadAddress: String,

@Schema(description = "지번 주소", example = "경기 성남시 분당구 백현동 532")
val jibunAddress: String,
) {
fun toDomain(): Address = Address(sido, sigungu, roadAddress, jibunAddress)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.damaba.damaba.adapter.inbound.common.dto

import com.damaba.common_file.domain.File
import io.swagger.v3.oas.annotations.media.Schema

data class FileRequest(
@Schema(description = "파일 이름", example = "apple.jpg")
val name: String,

@Schema(description = "파일 URL", example = "https://damaba-file-server/apple.jpg")
val url: String,
) {
fun toDomain(): File = File(name, url)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.damaba.damaba.adapter.inbound.common.dto

import io.swagger.v3.oas.annotations.media.Schema

data class FileResponse(
@Schema(description = "파일 이름", example = "apple.jpg")
val name: String,

@Schema(description = "파일 URL", example = "https://damaba-file-server/apple.jpg")
val url: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.security.SecurityRequirement
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.net.URI
Expand Down Expand Up @@ -58,10 +57,10 @@ class PromotionController(
description = "신규 프로모션을 등록합니다.",
security = [SecurityRequirement(name = "access-token")],
)
@PostMapping("/api/v1/promotions", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
@PostMapping("/api/v1/promotions")
fun postPromotionV1(
@AuthenticationPrincipal requestUser: User,
@ModelAttribute request: PostPromotionRequest,
@RequestBody request: PostPromotionRequest,
): ResponseEntity<PromotionResponse> {
val promotion = postPromotionUseCase.postPromotion(request.toCommand(requestUser.id))
return ResponseEntity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package com.damaba.damaba.adapter.inbound.promotion.dto

import com.damaba.common_exception.ValidationException
import com.damaba.common_file.domain.UploadFile
import com.damaba.damaba.adapter.inbound.common.dto.AddressRequest
import com.damaba.damaba.adapter.inbound.common.dto.FileRequest
import com.damaba.damaba.adapter.inbound.region.dto.RegionRequest
import com.damaba.damaba.application.port.inbound.promotion.PostPromotionUseCase
import com.damaba.damaba.domain.common.Address
import com.damaba.damaba.domain.promotion.constant.EventType
import com.damaba.damaba.domain.promotion.constant.PromotionType
import com.damaba.damaba.domain.region.Region
import io.swagger.v3.oas.annotations.media.Schema
import org.springframework.web.multipart.MultipartFile
import java.time.LocalDate

data class PostPromotionRequest(
Expand All @@ -24,17 +22,8 @@ data class PostPromotionRequest(
@Schema(description = "내용. 내용은 500 글자를 초과할 수 없습니다.", example = "이 이벤트는 오늘부터 시작해서...")
val content: String,

@Schema(description = "시/도 이름", example = "경기")
val sido: String,

@Schema(description = "시/군/구 이름", example = "성남시 분당구")
val sigungu: String,

@Schema(description = "도로명 주소. 도로명 주소와 지번 주소 중 최소 하나는 입력되어야 합니다.", example = "경기 성남시 분당구 판교역로 166")
val roadAddress: String,

@Schema(description = "지번 주소. 도로명 주소와 지번 주소 중 최소 하나는 입력되어야 합니다.", example = "경기 성남시 분당구 백현동 532")
val jibunAddress: String,
@Schema(description = "주소 정보")
val address: AddressRequest,

@Schema(description = "이벤트 관련 외부 링크", example = "https://promotion-instagram-post")
val externalLink: String?,
Expand All @@ -52,15 +41,10 @@ data class PostPromotionRequest(
val photographerInstagramId: String?,

@Schema(description = "이미지 리스트. 이미지는 최소 1장부터 최대 10장까지 첨부할 수 있습니다.")
val images: List<MultipartFile>,
val images: List<FileRequest>,

@Schema(
description = "<p>활동 지역 리스트. 활동 지역은 최소 1개 이상 선택해야 합니다." +
"<p>각 활동 지역은 <code>category</code>와 <code>name</code>으로 구성됩니다." +
"<p><code>category</code>와 <code>name</code>는 공백으로 구분된 하나의 문자열로 요청해야 합니다. (예시 데이터 참고)",
example = "[\"서울 강남구\", \"대전 서구\", \"경기 성남시 분당구\"]",
)
val activeRegions: Set<String>,
@Schema(description = "활동 지역 리스트. 활동 지역은 최소 1개 이상 선택해야 합니다.")
val activeRegions: Set<RegionRequest>,

@Schema(description = "해시태그 리스트", example = "[\"수원핫플\", \"스냅사진\"]")
val hashtags: Set<String>,
Expand All @@ -71,29 +55,14 @@ data class PostPromotionRequest(
eventType = eventType,
title = title,
content = content,
address = Address(sido, sigungu, roadAddress, jibunAddress),
address = address.toDomain(),
externalLink = externalLink,
startedAt = startedAt,
endedAt = endedAt,
photographerName = photographerName,
photographerInstagramId = photographerInstagramId,
images = images.map { multipartFile ->
UploadFile(
name = multipartFile.originalFilename,
size = multipartFile.size,
contentType = multipartFile.contentType,
inputStream = multipartFile.inputStream,
)
},
activeRegions = activeRegions.map { regionString ->
val firstSpaceIdx = regionString.indexOf(" ")
if (firstSpaceIdx == -1) {
throw ValidationException("전달된 activeRegions 요소가 잘못되었습니다. 형식은 \"category name\"이어야 합니다.")
}
val category = regionString.substring(0, firstSpaceIdx)
val name = regionString.substring(firstSpaceIdx + 1)
Region(category, name)
}.toSet(),
images = images.map { fileReq -> fileReq.toDomain() },
activeRegions = activeRegions.map { regionReq -> regionReq.toDomain() }.toSet(),
hashtags = hashtags,
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.damaba.damaba.adapter.inbound.promotion.dto

import com.damaba.damaba.adapter.inbound.common.dto.AddressResponse
import com.damaba.damaba.adapter.inbound.common.dto.FileResponse
import com.damaba.damaba.domain.promotion.Promotion
import com.damaba.damaba.domain.promotion.constant.EventType
import com.damaba.damaba.domain.promotion.constant.PromotionType
Expand Down Expand Up @@ -45,7 +46,7 @@ data class PromotionResponse(
val photographerInstagramId: String?,

@Schema(description = "이미지 url 리스트", example = "[\"https://promotion-image\"]")
val imageUrls: List<String>,
val images: List<FileResponse>,

@Schema(description = "활동 지역 리스트")
val activeRegions: Set<PromotionActiveRegionResponse>,
Expand All @@ -67,7 +68,7 @@ data class PromotionResponse(
endedAt = promotion.endedAt,
photographerName = promotion.photographerName,
photographerInstagramId = promotion.photographerInstagramId,
imageUrls = promotion.images.map { image -> image.url },
images = promotion.images.map { image -> FileResponse(image.name, image.url) },
activeRegions = promotion.activeRegions.map { PromotionActiveRegionResponse.from(it) }.toSet(),
hashtags = promotion.hashtags,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.damaba.damaba.adapter.inbound.region.dto

import com.damaba.damaba.domain.region.Region
import io.swagger.v3.oas.annotations.media.Schema

data class RegionRequest(
@Schema(description = "지역 카테고리", example = "서울")
val category: String,

@Schema(description = "지역 이름", example = "강남구")
val name: String,
) {
fun toDomain() = Region(category, name)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.damaba.damaba.adapter.outbound.common

import com.damaba.user.application.port.outbound.common.PublishEventPort
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component

Expand All @@ -8,8 +9,7 @@ import org.springframework.stereotype.Component
@Component
class SpringEventPublisher(
private val applicationEventPublisher: ApplicationEventPublisher,
) : com.damaba.user.application.port.outbound.common.PublishEventPort,
com.damaba.damaba.application.port.outbound.common.PublishEventPort {
) : PublishEventPort {
override fun publish(event: Any) {
applicationEventPublisher.publishEvent(event)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.damaba.damaba.application.port.inbound.promotion

import com.damaba.common_exception.ValidationException
import com.damaba.common_file.domain.UploadFile
import com.damaba.common_file.domain.File
import com.damaba.damaba.domain.common.Address
import com.damaba.damaba.domain.common.AddressValidator
import com.damaba.damaba.domain.promotion.Promotion
Expand Down Expand Up @@ -32,7 +32,7 @@ interface PostPromotionUseCase {
val endedAt: LocalDate?,
val photographerName: String?,
val photographerInstagramId: String?,
val images: List<UploadFile>,
val images: List<File>,
val activeRegions: Set<Region>,
val hashtags: Set<String>,
) {
Expand Down

This file was deleted.

Loading

0 comments on commit ae8f741

Please sign in to comment.