Skip to content

Commit

Permalink
feat: 이미지 3장 올리는 API 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
injoon2019 committed Sep 25, 2024
1 parent 9d8d9d0 commit 871785d
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ class UserProfileController(
private val profileFacade: UserProfileFacade,
) {

private val log = KotlinLogging.logger {}

@ApiOperation("온보딩 프로필 등록하기")
@PostMapping("/choice")
@AuthRequired
Expand All @@ -49,7 +47,6 @@ class UserProfileController(
@AuthUserId userId: Long,
@RequestBody registerIntroductionRequest: RegisterIntroductionRequest
) {
log.info { "자기 소개 등록하기 호출" }
profileFacade.upsertIntroduction(userId, registerIntroductionRequest)
}

Expand All @@ -64,7 +61,6 @@ class UserProfileController(
@PostMapping("/images")
@AuthRequired
fun uploadImage(@AuthUserId userId: Long, @RequestPart file: MultipartFile) {
log.info { "사진 등록하기 호출" }
profileFacade.uploadImage(userId, file)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.nexters.bottles.api.user.controller

import com.nexters.bottles.api.global.interceptor.AuthRequired
import com.nexters.bottles.api.global.resolver.AuthUserId
import com.nexters.bottles.api.user.facade.UserProfileFacade
import com.nexters.bottles.api.user.facade.UserProfileFacadeV2
import com.nexters.bottles.api.user.facade.dto.ActivateMatchingRequest
import com.nexters.bottles.api.user.facade.dto.ExistIntroductionResponse
import com.nexters.bottles.api.user.facade.dto.ProfileChoiceResponse
import com.nexters.bottles.api.user.facade.dto.RegisterIntroductionRequest
import com.nexters.bottles.api.user.facade.dto.RegisterProfileRequest
import com.nexters.bottles.api.user.facade.dto.UserInfoResponse
import com.nexters.bottles.api.user.facade.dto.UserProfileResponse
import com.nexters.bottles.api.user.facade.dto.UserProfileStatusResponse
import io.swagger.annotations.ApiOperation
import mu.KotlinLogging
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile

@RestController
@RequestMapping("/api/v2/profile")
class UserProfileControllerV2(
private val profileFacadeV2: UserProfileFacadeV2,
) {

@ApiOperation("마이페이지 자기소개 & 사진들 등록/수정하기")
@PostMapping("/introduction-images")
@AuthRequired
fun upsertIntroductionAndImages(
@AuthUserId userId: Long,
@RequestBody registerIntroductionRequest: RegisterIntroductionRequest,
@RequestPart files: List<MultipartFile>
) {
profileFacadeV2.upsertIntroductionAndImages(userId, registerIntroductionRequest, files)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.nexters.bottles.api.user.facade

import com.nexters.bottles.api.user.facade.dto.ActivateMatchingRequest
import com.nexters.bottles.api.user.facade.dto.ExistIntroductionResponse
import com.nexters.bottles.api.user.facade.dto.ProfileChoiceResponse
import com.nexters.bottles.api.user.facade.dto.RegisterIntroductionRequest
import com.nexters.bottles.api.user.facade.dto.RegisterProfileRequest
import com.nexters.bottles.api.user.facade.dto.UserInfoResponse
import com.nexters.bottles.api.user.facade.dto.UserProfileResponse
import com.nexters.bottles.api.user.facade.dto.UserProfileStatus
import com.nexters.bottles.api.user.facade.dto.UserProfileStatusResponse
import com.nexters.bottles.app.common.component.FileService
import com.nexters.bottles.app.common.component.ImageUploader
import com.nexters.bottles.app.user.domain.User
import com.nexters.bottles.app.user.domain.UserProfile
import com.nexters.bottles.app.user.domain.UserProfileSelect
import com.nexters.bottles.app.user.service.BlockContactListService
import com.nexters.bottles.app.user.service.UserProfileService
import com.nexters.bottles.app.user.service.UserService
import com.nexters.bottles.app.user.service.dto.SignInUpStep
import com.nexters.bottles.app.user.service.dto.SignInUpStep.SIGN_UP_APPLE_LOGIN_FINISHED
import com.nexters.bottles.app.user.service.dto.SignInUpStep.SIGN_UP_NAME_GENDER_AGE_FINISHED
import mu.KotlinLogging
import org.springframework.stereotype.Component
import org.springframework.web.multipart.MultipartFile
import regions
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

@Component
class UserProfileFacadeV2(
private val profileService: UserProfileService,
private val fileService: FileService,
private val imageUploader: ImageUploader,
) {

private val log = KotlinLogging.logger { }

fun upsertIntroductionAndImages(
userId: Long,
registerIntroductionRequest: RegisterIntroductionRequest,
files: List<MultipartFile>
) {
validateIntroduction(registerIntroductionRequest)

profileService.saveIntroduction(userId, registerIntroductionRequest.introduction)

val paths = files.map { makePathWithUserId(it, userId) }
val originalImageUrls = files.zip(paths)
.map { (file, path) -> fileService.upload(file, path) }
.map { it.toString() }
val blurredImageUrl = imageUploader.uploadWithBlur(files[0], paths[0]);

profileService.uploadImageUrls(userId, originalImageUrls, blurredImageUrl.toString())
}

private fun validateIntroduction(introductionDto: RegisterIntroductionRequest) {
introductionDto.introduction.forEach {
require(it.answer.length >= 30 && it.answer.length <= 300) {
"소개는 30자 이상 300자 이하로 써야 해요"
}
}
}

fun makePathWithUserId(
file: MultipartFile,
userId: Long
) = "" + userId + FILE_NAME_DELIMITER + LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + FILE_NAME_DELIMITER + file.originalFilename

companion object {
private const val FILE_NAME_DELIMITER = "_"
}
}
1 change: 1 addition & 0 deletions api/src/main/resources/sql/ddl/table_query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ CREATE TABLE user_profile
profile_select JSON,
introduction JSON,
image_url VARCHAR(2048),
images JSON,
blurred_image_url VARCHAR(2048),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class UserProfile(

var imageUrl: String? = null,

@Convert(converter = QuestionAndAnswerConverter::class)
var imageUrls: List<String> = arrayListOf(),

var blurredImageUrl: String? = null,
) : BaseEntity() {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.nexters.bottles.app.user.repository.converter

import com.fasterxml.jackson.databind.ObjectMapper
import com.nexters.bottles.app.config.JacksonConfig.Companion.kotlinModule
import com.nexters.bottles.app.user.domain.QuestionAndAnswer
import javax.persistence.AttributeConverter
import javax.persistence.Converter

@Converter(autoApply = true)
class ImagesConverter : AttributeConverter<List<String>, String> {

private val objectMapper = ObjectMapper().registerModule(kotlinModule)

override fun convertToDatabaseColumn(attribute: List<String>?): String? {
return attribute?.let { objectMapper.writeValueAsString(it) }
}

override fun convertToEntityAttribute(dbData: String?): List<String>? {
return dbData?.let {
objectMapper.readValue(
it,
objectMapper.typeFactory.constructCollectionType(List::class.java, String::class.java)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ class UserProfileService(
fun uploadImageUrl(user: User, imageUrl: String, blurredImageUrl: String) {
profileRepository.findByUserId(user.id)?.let {
it.imageUrl = imageUrl
it.imageUrls = listOf(imageUrl)
it.blurredImageUrl = blurredImageUrl
} ?: throw IllegalArgumentException("고객센터에 문의해주세요")
}

@Transactional
fun uploadImageUrls(userId: Long, imageUrls: List<String>, blurredImageUrl: String) {
profileRepository.findByUserId(userId)?.let {
it.imageUrls = imageUrls
it.blurredImageUrl = blurredImageUrl
} ?: throw IllegalArgumentException("고객센터에 문의해주세요")
}
Expand Down

0 comments on commit 871785d

Please sign in to comment.