97 lines
4.1 KiB
Kotlin
97 lines
4.1 KiB
Kotlin
package net.halfbinary.scavengerhuntapi.service
|
|
|
|
import net.coobird.thumbnailator.Thumbnails
|
|
import net.coobird.thumbnailator.tasks.UnsupportedFormatException
|
|
import net.halfbinary.scavengerhuntapi.error.exception.BadFileException
|
|
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.PhotoId
|
|
import net.halfbinary.scavengerhuntapi.model.PhotoStatus
|
|
import net.halfbinary.scavengerhuntapi.model.TeamId
|
|
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.http.MediaType
|
|
import org.springframework.stereotype.Service
|
|
import org.springframework.web.multipart.MultipartFile
|
|
import java.io.ByteArrayInputStream
|
|
import java.io.ByteArrayOutputStream
|
|
import java.time.LocalDateTime
|
|
|
|
@Service
|
|
class PhotoService(
|
|
private val photoRepository: PhotoRepository,
|
|
private val hunterService: HunterService,
|
|
private val teamService: TeamService,
|
|
private val s3StorageService: S3StorageService,
|
|
private val fileProbeService: FileProbeService
|
|
) {
|
|
fun submitPhoto(huntId: HuntId, itemId: ItemId, email: String, file: MultipartFile) {
|
|
val originalBytes = file.bytes
|
|
val fileType = fileProbeService.getFileType(originalBytes)
|
|
|
|
if(!fileProbeService.isImageType(fileType)) throw BadFileException("Not an image")
|
|
|
|
val originalAsJpeg = try {
|
|
toJpeg(file.bytes)
|
|
} catch (_: UnsupportedFormatException) {
|
|
throw BadFileException("Image type is not supported")
|
|
}
|
|
|
|
val hunter = hunterService.getHunterByEmail(email)
|
|
val now = LocalDateTime.now()
|
|
val photo = Photo(
|
|
itemId = itemId,
|
|
huntId = huntId,
|
|
hunterId = hunter.id,
|
|
foundDateTime = now,
|
|
status = PhotoStatus.SUBMITTED,
|
|
statusChangeDateTime = now
|
|
)
|
|
val savedRecord = photoRepository.save(photo.toRecord())
|
|
val baseName = savedRecord.id.toString()
|
|
|
|
s3StorageService.upload("$baseName${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)
|
|
}
|
|
|
|
fun getPhotoInfo(huntId: HuntId, teamId: TeamId, itemId: ItemId, photoId: PhotoId, email: String): PhotoResponse {
|
|
val requestingHunter = hunterService.getHunterByEmail(email)
|
|
val photoRecord = photoRepository.findByIdAndItemIdAndHuntId(photoId, itemId, huntId)
|
|
?: throw NotFoundException("Photo not found")
|
|
|
|
if (!requestingHunter.isAdmin) {
|
|
val team = teamService.getTeamForHunterInHunt(huntId, email)
|
|
if (team.id != teamId) throw ForbiddenException("Access denied")
|
|
}
|
|
|
|
val submitter = hunterService.getHunterById(photoRecord.hunterId)
|
|
return photoRecord.toDomain().toResponse(submitter)
|
|
}
|
|
|
|
private fun toJpeg(bytes: ByteArray): ByteArray {
|
|
val output = ByteArrayOutputStream()
|
|
Thumbnails.of(ByteArrayInputStream(bytes))
|
|
.scale(1.0)
|
|
.outputFormat("jpg")
|
|
.toOutputStream(output)
|
|
return output.toByteArray()
|
|
}
|
|
|
|
private fun resize(bytes: ByteArray, width: Int): ByteArray {
|
|
val output = ByteArrayOutputStream()
|
|
Thumbnails.of(ByteArrayInputStream(bytes))
|
|
.width(width)
|
|
.outputFormat("jpg")
|
|
.toOutputStream(output)
|
|
return output.toByteArray()
|
|
}
|
|
}
|