diff --git a/Storage/storage-app/src/main/kotlin/co/nilin/opex/storage/app/controller/FileController.kt b/Storage/storage-app/src/main/kotlin/co/nilin/opex/storage/app/controller/FileController.kt index 545317bc4..a8216d35d 100644 --- a/Storage/storage-app/src/main/kotlin/co/nilin/opex/storage/app/controller/FileController.kt +++ b/Storage/storage-app/src/main/kotlin/co/nilin/opex/storage/app/controller/FileController.kt @@ -1,6 +1,7 @@ package co.nilin.opex.storage.app.controller import co.nilin.opex.storage.app.service.StorageService +import co.nilin.opex.storage.app.service.StringToHashService import co.nilin.opex.utility.error.data.OpexError import co.nilin.opex.utility.error.data.OpexException import kotlinx.coroutines.reactive.awaitFirstOrNull @@ -13,38 +14,29 @@ import org.springframework.web.bind.annotation.* import reactor.core.publisher.Mono import java.net.URLConnection import java.nio.file.Paths -import kotlin.io.path.exists +import java.util.* @RestController -class FileController(private val storageService: StorageService) { +class FileController(private val storageService: StorageService, private val stringToHashService: StringToHashService) { data class FileUploadResponse(val path: String) - @PostMapping("/{uid}") - suspend fun fileUpload( - @PathVariable("uid") uid: String, - @RequestPart("file") file: Mono, - @CurrentSecurityContext securityContext: SecurityContext - ): Any { - if (securityContext.authentication.name != uid) throw OpexException(OpexError.UnAuthorized) - file.awaitFirstOrNull().apply { - if (this == null) throw OpexException(OpexError.BadRequest, "File Not Provided") - val ext = this.filename().replace(Regex(".+(?=\\..+)"), "") - if (ext.toLowerCase() !in listOf(".jpg", ".jpeg", ".png", ".mp4", ".mov", ".pdf", ".svg")) - throw OpexException(OpexError.BadRequest, "Invalid File Format") - val path = Paths.get("").resolve("/opex-storage/$uid/${this.filename()}").toString() - storageService.store(path, this) - return FileUploadResponse("/$uid/${this.filename()}") + private suspend fun upload(uid: String, file: FilePart?, nameWithoutExtension: String? = null): FileUploadResponse { + if (file == null) throw OpexException(OpexError.BadRequest, "File Not Provided") + val filename = file.filename() + val ext = filename.replace(Regex(".+(?<=\\.)"), "") + if (ext.toLowerCase() !in listOf("jpg", "jpeg", "png", "mp4", "mov", "pdf", "gif")) + throw OpexException(OpexError.BadRequest, "Invalid File Format") + val uri = if (nameWithoutExtension == null) { + "$uid/$filename" + } else { + "$uid/$nameWithoutExtension.$ext" } + val path = Paths.get("").resolve("/opex-storage/$uri").toString() + storageService.store(path, file) + return FileUploadResponse("/$uri") } - @GetMapping("/{uid}/{filename}") - @ResponseBody - suspend fun fileDownload( - @PathVariable("uid") uid: String, - @PathVariable("filename") filename: String, - @CurrentSecurityContext securityContext: SecurityContext - ): ResponseEntity { - if (securityContext.authentication.name != uid) throw OpexException(OpexError.UnAuthorized) + private suspend fun download(uid: String, filename: String? = null): ResponseEntity { val path = Paths.get("").resolve("/opex-storage/$uid/$filename") if (!storageService.exists(path.toString())) throw OpexException(OpexError.NotFound) val file = storageService.load(path.toString()) @@ -52,16 +44,33 @@ class FileController(private val storageService: StorageService) { return ResponseEntity.ok().contentType(MediaType.parseMediaType(mimeType)).body(file.readBytes()) } + @PostMapping("/{uid}") + suspend fun fileUploadPost( + @PathVariable("uid") uid: String, + @RequestPart("file") file: Mono, + @CurrentSecurityContext securityContext: SecurityContext + ): FileUploadResponse { + if (securityContext.authentication.name != uid) throw OpexException(OpexError.UnAuthorized) + return upload(uid, file.awaitFirstOrNull(), stringToHashService.digest(UUID.randomUUID().toString())) + } + + @GetMapping("/{uid}/{filename}") + @ResponseBody + suspend fun download( + @PathVariable("uid") uid: String, + @PathVariable("filename") filename: String, + @CurrentSecurityContext securityContext: SecurityContext + ): ResponseEntity { + if (securityContext.authentication.name != uid) throw OpexException(OpexError.UnAuthorized) + return download(uid, filename) + } + @GetMapping("/admin/download/{uid}/{filename}") @ResponseBody suspend fun adminFileDownload( - @PathVariable("uid") uid: String, - @PathVariable("filename") filename: String + @PathVariable("uid") uid: String, + @PathVariable("filename") filename: String ): ResponseEntity { - val path = Paths.get("").resolve("/opex-storage/$uid/$filename") - if (!storageService.exists(path.toString())) throw OpexException(OpexError.NotFound) - val file = storageService.load(path.toString()) - val mimeType = URLConnection.getFileNameMap().getContentTypeFor(path.fileName.toString()) - return ResponseEntity.ok().contentType(MediaType.parseMediaType(mimeType)).body(file.readBytes()) + return download(uid, filename) } } diff --git a/Storage/storage-app/src/main/kotlin/co/nilin/opex/storage/app/service/StringToHashService.kt b/Storage/storage-app/src/main/kotlin/co/nilin/opex/storage/app/service/StringToHashService.kt new file mode 100644 index 000000000..ab0555692 --- /dev/null +++ b/Storage/storage-app/src/main/kotlin/co/nilin/opex/storage/app/service/StringToHashService.kt @@ -0,0 +1,14 @@ +package co.nilin.opex.storage.app.service + +import org.springframework.stereotype.Service +import java.util.zip.CRC32 + +@Service +class StringToHashService { + private val crc32 = CRC32() + + fun digest(input: String): String { + crc32.update(input.toByteArray()) + return String.format("%02x", crc32.value) + } +}