Skip to content

Commit 1dc0af6

Browse files
authored
Merge pull request #26 from prgrms-web-devcourse-final-project/quiz-image
[QUZ-84][FEATURE] Quiz Image API
2 parents 49fb246 + f2f4f08 commit 1dc0af6

File tree

19 files changed

+306
-1
lines changed

19 files changed

+306
-1
lines changed

gateway-service/src/main/kotlin/com/grepp/quizy/config/RedisConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.grepp.quizy.user.infra.redis.config
1+
package com.grepp.quizy.config
22

33
import org.springframework.beans.factory.annotation.Value
44
import org.springframework.context.annotation.Bean
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.grepp.quizy.quiz.api.image
2+
3+
import com.grepp.quizy.quiz.domain.image.ImageFile
4+
import org.springframework.web.multipart.MultipartFile
5+
6+
fun toImageFile(file: MultipartFile): ImageFile {
7+
val contentType = file.contentType ?: throw IllegalArgumentException("File content type is null")
8+
return ImageFile(contentType, file.inputStream)
9+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.grepp.quizy.quiz.api.image
2+
3+
import com.grepp.quizy.common.api.ApiResponse
4+
import com.grepp.quizy.quiz.domain.image.QuizImage
5+
import com.grepp.quizy.quiz.domain.image.QuizImageService
6+
import org.springframework.http.MediaType
7+
import org.springframework.web.bind.annotation.PostMapping
8+
import org.springframework.web.bind.annotation.RequestMapping
9+
import org.springframework.web.bind.annotation.RequestPart
10+
import org.springframework.web.bind.annotation.RestController
11+
import org.springframework.web.multipart.MultipartFile
12+
13+
@RestController
14+
@RequestMapping("/api/quiz/images")
15+
class QuizImageApi(
16+
private val quizImageService: QuizImageService
17+
) {
18+
19+
@PostMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
20+
fun uploadImage(@RequestPart file: MultipartFile): ApiResponse<QuizImage> =
21+
ApiResponse.success(quizImageService.uploadImage(toImageFile(file)))
22+
23+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.grepp.quizy.quiz.domain.image
2+
3+
import java.io.InputStream
4+
5+
data class ImageFile(
6+
val contentType: String,
7+
val inputStream: InputStream
8+
) {
9+
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.grepp.quizy.quiz.domain.image
2+
3+
data class QuizImage(
4+
val url: String,
5+
val id: Long = 0,
6+
) {
7+
companion object {
8+
fun from(url: String): QuizImage {
9+
return QuizImage(url)
10+
}
11+
}
12+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.grepp.quizy.quiz.domain.image
2+
3+
import com.grepp.quizy.quiz.domain.image.exception.QuizImageDomainException
4+
import org.springframework.stereotype.Component
5+
6+
@Component
7+
class QuizImageManager(
8+
private val quizImageRepository: QuizImageRepository
9+
) {
10+
fun append(image: QuizImage): QuizImage {
11+
return quizImageRepository.save(image)
12+
}
13+
14+
fun read(id: Long): QuizImage {
15+
return quizImageRepository.findById(id) ?: throw QuizImageDomainException.NotFound
16+
}
17+
18+
fun delete(id: Long) {
19+
quizImageRepository.deleteById(id)
20+
}
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.grepp.quizy.quiz.domain.image
2+
3+
interface QuizImageRepository {
4+
5+
fun save(image: QuizImage): QuizImage
6+
7+
fun findById(id: Long): QuizImage?
8+
9+
fun deleteById(id: Long)
10+
11+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.grepp.quizy.quiz.domain.image
2+
3+
import org.springframework.stereotype.Service
4+
5+
@Service
6+
class QuizImageService(
7+
private val quizImageUploader: QuizImageUploader,
8+
private val quizImageAppender: QuizImageManager
9+
) {
10+
11+
fun uploadImage(imageFile: ImageFile): QuizImage {
12+
val quizImage = quizImageUploader.upload(imageFile)
13+
return quizImageAppender.append(quizImage)
14+
}
15+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.grepp.quizy.quiz.domain.image
2+
3+
interface QuizImageUploader {
4+
fun upload(imageFile: ImageFile): QuizImage
5+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.grepp.quizy.quiz.domain.image.exception
2+
3+
import com.grepp.quizy.common.exception.DomainException
4+
5+
sealed class QuizImageDomainException(
6+
errorCode: QuizImageErrorCode
7+
) : DomainException(errorCode) {
8+
9+
data object NotFound : QuizImageDomainException(QuizImageErrorCode.IMAGE_NOT_FOUND_ERROR) {
10+
private fun readResolve(): Any = NotFound
11+
}
12+
}

0 commit comments

Comments
 (0)