Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add temporary file upload #55

Merged
merged 14 commits into from
Jan 5, 2023
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(
alexstaeding marked this conversation as resolved.
Show resolved Hide resolved
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