Skip to content

Commit

Permalink
Add temporary file upload (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
djfhe committed Jan 5, 2023
1 parent b26b2d8 commit 88ad454
Show file tree
Hide file tree
Showing 54 changed files with 1,192 additions and 110 deletions.
31 changes: 31 additions & 0 deletions application/src/jvmMain/kotlin/replace/dto/FileDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package replace.dto

import kotlinx.serialization.Serializable
import replace.model.File

@Serializable
class FileDto(
override val id: String? = null,
val name: String,
val path: String,
val extension: String,
val sizeInBytes: Long,
val mime: String? = null,
) : Dto

fun File.toDto() = FileDto(
id = id?.toHexString(),
name = name,
path = path,
extension = extension,
sizeInBytes = sizeInBytes,
mime = mime,
)

fun FileDto.toModel() = File(
name = name,
path = path,
extension = extension,
sizeInBytes = sizeInBytes,
mime = mime,
)
37 changes: 37 additions & 0 deletions application/src/jvmMain/kotlin/replace/dto/FileUploadDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package replace.dto

import kotlinx.serialization.Serializable
import replace.datastore.FileRepository
import replace.datastore.FileStorage
import replace.datastore.TemporaryFileRepository
import replace.usecase.temporaryfileupload.SaveTemporaryFileUploadPersistentUseCase

@Serializable
class FileUploadDto(
override val id: String,
val temporary: Boolean,
) : Dto

suspend fun FileUploadDto.save(
temporaryFileRepository: TemporaryFileRepository,
fileRepository: FileRepository,
fileStorage: FileStorage,
): FileUploadDto {
if (!temporary) {
return this
}

val file = SaveTemporaryFileUploadPersistentUseCase.execute(
id,
temporaryFileRepository,
fileRepository,
fileStorage,
)

checkNotNull(file.id) { "Could not save file" }

return FileUploadDto(
id = file.id,
temporary = false,
)
}
53 changes: 47 additions & 6 deletions application/src/jvmMain/kotlin/replace/dto/FloorDto.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,60 @@ package replace.dto

import kotlinx.serialization.Serializable
import org.bson.types.ObjectId
import replace.datastore.FileRepository
import replace.datastore.FileStorage
import replace.datastore.TemporaryFileRepository
import replace.model.Floor

@Serializable
class FloorDto(
override val id: String? = null,
val name: String,
val siteId: String,
val planFile: FileUploadDto? = null,
) : Dto

fun Floor.toDto() = FloorDto(
id = id?.toHexString(),
name = name,
siteId = siteId.toHexString(),
)
fun Floor.toDto(): FloorDto {

fun FloorDto.toModel() = Floor(name, ObjectId(siteId))
val fileId = planFileId?.toHexString()
?: return FloorDto(
id = id?.toHexString(),
name = name,
siteId = siteId.toHexString(),
)

return FloorDto(
id = id?.toHexString(),
name = name,
siteId = siteId.toHexString(),
planFile = FileUploadDto(
id = fileId,
temporary = false,
),
)
}

fun FloorDto.toModel(): Floor {
return Floor(
name = name,
siteId = ObjectId(siteId),
planFileId = planFile?.let { ObjectId(planFile.id) },
)
}

suspend fun FloorDto.saveFiles(
temporaryFileRepository: TemporaryFileRepository,
fileRepository: FileRepository,
fileStorage: FileStorage
): FloorDto {
return FloorDto(
id = id,
name = name,
siteId = siteId,
planFile = planFile?.save(
temporaryFileRepository = temporaryFileRepository,
fileRepository = fileRepository,
fileStorage = fileStorage,
),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package replace.dto

import kotlinx.serialization.Serializable
import replace.model.TemporaryFile
import java.time.LocalDateTime

@Serializable
class TemporaryFileUploadDto(
override val id: String? = null,
val name: String,
val path: String,
val mime: String? = null,
val extension: String,
val sizeInBytes: Long,
val createdAt: String,
) : Dto

fun TemporaryFile.toDto() = TemporaryFileUploadDto(
id = id?.toHexString(),
name = name,
path = path,
mime = mime,
extension = extension,
sizeInBytes = sizeInBytes,
createdAt = createdAt.toString()
)

fun TemporaryFileUploadDto.toModel() = TemporaryFile(
name = name,
path = path,
extension = extension,
mime = mime,
sizeInBytes = sizeInBytes,
createdAt = LocalDateTime.parse(createdAt)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package replace.usecase.file

import org.bson.types.ObjectId
import replace.datastore.FileRepository
import replace.datastore.FileStorage
import replace.datastore.TemporaryFileRepository
import replace.dto.FileDto
import replace.dto.toDto
import replace.model.File
import java.util.UUID

object CreateFileUseCase {

suspend fun execute(
temporaryFileUploadId: String,
temporaryFileRepository: TemporaryFileRepository,
fileRepository: FileRepository,
fileStorage: FileStorage,
): FileDto {
if (!ObjectId.isValid(temporaryFileUploadId)) {
throw IllegalArgumentException("Id $temporaryFileUploadId is not a valid ObjectId")
}

val temporaryFileUpload = temporaryFileRepository.findOneById(ObjectId(temporaryFileUploadId))
?: throw IllegalArgumentException("Temporary file upload with id $temporaryFileUploadId not found")

val newFilePath = "uploads/${UUID.randomUUID()}/base.${temporaryFileUpload.extension}"

if (!fileStorage.copyFile(temporaryFileUpload.path, newFilePath)) {
throw IllegalStateException("Could not copy file from ${temporaryFileUpload.path} to $newFilePath")
}

val file = File(
name = temporaryFileUpload.name,
path = newFilePath,
mime = temporaryFileUpload.mime,
extension = temporaryFileUpload.extension,
sizeInBytes = fileStorage.getFileSize(newFilePath),
)

val insertedFile = fileRepository.insertOne(file)

checkNotNull(insertedFile) { "Could not insert File into Database" }

return insertedFile.toDto()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package replace.usecase.file

import org.bson.types.ObjectId
import replace.datastore.FileRepository
import replace.datastore.FileStorage

object DeleteFileUseCase {

suspend fun execute(
fileId: String,
fileRepository: FileRepository,
fileStorage: FileStorage,
) {
if (!ObjectId.isValid(fileId)) {
throw IllegalArgumentException("Id $fileId: is not a valid ObjectId")
}

val file = fileRepository.findOneById(ObjectId(fileId))
?: throw IllegalArgumentException("File with id $fileId not found")

if (fileStorage.deleteFile(file.path)) {
fileRepository.deleteOneById(ObjectId(fileId))
} else {
throw IllegalStateException("Could not delete file with id $fileId")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package replace.usecase.floor

import org.bson.types.ObjectId
import replace.datastore.FileRepository
import replace.datastore.FileStorage
import replace.datastore.FloorRepository
import replace.datastore.SiteRepository
import replace.datastore.TemporaryFileRepository
import replace.dto.FloorDto
import replace.dto.toDto
import replace.dto.toModel
Expand All @@ -12,12 +15,26 @@ object CreateFloorUseCase {
floorDto: FloorDto,
floorRepository: FloorRepository,
siteRepository: SiteRepository,
temporaryFileRepository: TemporaryFileRepository,
fileRepository: FileRepository,
fileStorage: FileStorage,
): FloorDto {
val siteId = ObjectId(floorDto.siteId)
val site = siteRepository.findOneById(siteId)
checkNotNull(site) { "Site with id $siteId not found" }
val insertedFloor = floorRepository.insertOne(floorDto.toModel())

val floorDtoWithPlan = SaveFloorPlanFileUseCase.execute(
floorDto,
floorRepository,
temporaryFileRepository,
fileRepository,
fileStorage,
)

val insertedFloor = floorRepository.insertOne(floorDtoWithPlan.toModel())

checkNotNull(insertedFloor) { "Could not insert BookableEntity" }

return insertedFloor.toDto()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package replace.usecase.floor

import org.bson.types.ObjectId
import replace.datastore.FileRepository
import replace.datastore.FileStorage
import replace.datastore.FloorRepository
import replace.datastore.TemporaryFileRepository
import replace.dto.FloorDto
import replace.dto.saveFiles
import replace.usecase.file.DeleteFileUseCase

object SaveFloorPlanFileUseCase {
suspend fun execute(
floorDto: FloorDto,
floorRepository: FloorRepository,
temporaryFileRepository: TemporaryFileRepository,
fileRepository: FileRepository,
fileStorage: FileStorage,
): FloorDto {
val oldPlanFileId = floorDto.id?.let { floorRepository.findOneById(ObjectId(it)) }?.planFileId?.toHexString()

val saved = floorDto.saveFiles(
temporaryFileRepository = temporaryFileRepository,
fileRepository = fileRepository,
fileStorage = fileStorage,
)

if (oldPlanFileId != saved.planFile?.id) {
oldPlanFileId?.let { DeleteFileUseCase.execute(it, fileRepository, fileStorage) }
}

return saved
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package replace.usecase.floor

import org.bson.types.ObjectId
import replace.datastore.FileRepository
import replace.datastore.FileStorage
import replace.datastore.FloorRepository
import replace.datastore.TemporaryFileRepository
import replace.dto.FloorDto
import replace.dto.toDto
import replace.dto.toModel
Expand All @@ -10,12 +13,23 @@ object UpdateFloorUseCase {
suspend fun execute(
dto: FloorDto,
repository: FloorRepository,
temporaryFileRepository: TemporaryFileRepository,
fileRepository: FileRepository,
fileStorage: FileStorage,
): FloorDto {
val floorId = ObjectId(dto.id)

val updatedModel = repository.updateOne(floorId, dto.toModel())
val floorDtoWithPlan = SaveFloorPlanFileUseCase.execute(
dto,
repository,
temporaryFileRepository,
fileRepository,
fileStorage,
)

checkNotNull(updatedModel) { "Could not update Floor" }
val updatedModel = repository.updateOne(floorId, floorDtoWithPlan.toModel())

checkNotNull(updatedModel) { "Could not update Floor with id $floorId\n$floorDtoWithPlan" }

return updatedModel.toDto()
}
Expand Down

0 comments on commit 88ad454

Please sign in to comment.