Adds image retrieval endpoint
This commit is contained in:
@@ -7,15 +7,19 @@ import net.halfbinary.scavengerhuntapi.error.exception.ForbiddenException
|
||||
import net.halfbinary.scavengerhuntapi.error.exception.NotFoundException
|
||||
import net.halfbinary.scavengerhuntapi.model.HuntId
|
||||
import net.halfbinary.scavengerhuntapi.model.ItemId
|
||||
import net.halfbinary.scavengerhuntapi.model.ImageVersion
|
||||
import net.halfbinary.scavengerhuntapi.model.PhotoId
|
||||
import net.halfbinary.scavengerhuntapi.model.PhotoStatus
|
||||
import net.halfbinary.scavengerhuntapi.model.TeamId
|
||||
import net.halfbinary.scavengerhuntapi.model.domain.PhotoFile
|
||||
import net.halfbinary.scavengerhuntapi.model.converter.toDomain
|
||||
import net.halfbinary.scavengerhuntapi.model.converter.toRecord
|
||||
import net.halfbinary.scavengerhuntapi.model.converter.toResponse
|
||||
import net.halfbinary.scavengerhuntapi.model.domain.Photo
|
||||
import net.halfbinary.scavengerhuntapi.model.response.PhotoResponse
|
||||
import net.halfbinary.scavengerhuntapi.repository.PhotoRepository
|
||||
import org.springframework.core.io.InputStreamResource
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
@@ -56,7 +60,7 @@ class PhotoService(
|
||||
val savedRecord = photoRepository.save(photo.toRecord())
|
||||
val baseName = savedRecord.id.toString()
|
||||
|
||||
s3StorageService.upload("$baseName${fileProbeService.getFileExtension(fileType)}", originalBytes, fileType)
|
||||
s3StorageService.upload("${baseName}_original${fileProbeService.getFileExtension(fileType)}", originalBytes, fileType)
|
||||
s3StorageService.upload("${baseName}_large.jpg", originalAsJpeg, MediaType.IMAGE_JPEG_VALUE)
|
||||
s3StorageService.upload("${baseName}_medium.jpg", resize(originalBytes, 800), MediaType.IMAGE_JPEG_VALUE)
|
||||
s3StorageService.upload("${baseName}_small.jpg", resize(originalBytes, 200), MediaType.IMAGE_JPEG_VALUE)
|
||||
@@ -76,6 +80,29 @@ class PhotoService(
|
||||
return photoRecord.toDomain().toResponse(submitter)
|
||||
}
|
||||
|
||||
fun getPhotoFile(photoId: PhotoId, email: String, version: ImageVersion = ImageVersion.LARGE): PhotoFile {
|
||||
val requestingHunter = hunterService.getHunterByEmail(email)
|
||||
val photoRecord = photoRepository.findByIdOrNull(photoId)
|
||||
?: throw NotFoundException("Photo not found")
|
||||
|
||||
if (!requestingHunter.isAdmin) {
|
||||
val submitter = hunterService.getHunterById(photoRecord.hunterId)
|
||||
val requestingTeam = teamService.getTeamForHunterInHunt(photoRecord.huntId, requestingHunter.email)
|
||||
val submitterTeam = teamService.getTeamForHunterInHunt(photoRecord.huntId, submitter.email)
|
||||
if (requestingTeam.id != submitterTeam.id) throw ForbiddenException("Access denied")
|
||||
}
|
||||
|
||||
val key = when (version) {
|
||||
ImageVersion.ORIGINAL -> s3StorageService.findKeyByPrefix("${photoId}_original")
|
||||
?: throw NotFoundException("Photo file not found")
|
||||
ImageVersion.LARGE -> "${photoId}_large.jpg"
|
||||
ImageVersion.MEDIUM -> "${photoId}_medium.jpg"
|
||||
ImageVersion.SMALL -> "${photoId}_small.jpg"
|
||||
}
|
||||
val (stream, contentType) = s3StorageService.download(key)
|
||||
return PhotoFile(InputStreamResource(stream), MediaType.parseMediaType(contentType))
|
||||
}
|
||||
|
||||
private fun toJpeg(bytes: ByteArray): ByteArray {
|
||||
val output = ByteArrayOutputStream()
|
||||
Thumbnails.of(ByteArrayInputStream(bytes))
|
||||
|
||||
@@ -4,7 +4,10 @@ import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.stereotype.Service
|
||||
import software.amazon.awssdk.core.sync.RequestBody
|
||||
import software.amazon.awssdk.services.s3.S3Client
|
||||
import software.amazon.awssdk.services.s3.model.GetObjectRequest
|
||||
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request
|
||||
import software.amazon.awssdk.services.s3.model.PutObjectRequest
|
||||
import java.io.InputStream
|
||||
|
||||
@Service
|
||||
class S3StorageService(
|
||||
@@ -22,4 +25,25 @@ class S3StorageService(
|
||||
RequestBody.fromBytes(bytes)
|
||||
)
|
||||
}
|
||||
|
||||
fun findKeyByPrefix(prefix: String): String? {
|
||||
val response = s3Client.listObjectsV2(
|
||||
ListObjectsV2Request.builder()
|
||||
.bucket(bucket)
|
||||
.prefix(prefix)
|
||||
.maxKeys(1)
|
||||
.build()
|
||||
)
|
||||
return response.contents().firstOrNull()?.key()
|
||||
}
|
||||
|
||||
fun download(key: String): Pair<InputStream, String> {
|
||||
val response = s3Client.getObject(
|
||||
GetObjectRequest.builder()
|
||||
.bucket(bucket)
|
||||
.key(key)
|
||||
.build()
|
||||
)
|
||||
return Pair(response, response.response().contentType())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user