diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/ModuleInitializer.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/ModuleInitializer.kt index b0b2985..de897ab 100644 --- a/api/src/main/kotlin/com/cubetiqs/web/modules/ModuleInitializer.kt +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/ModuleInitializer.kt @@ -1,7 +1,7 @@ package com.cubetiqs.web.modules -import com.cubetiqs.web.modules.uploader.FileStorageFactory -import com.cubetiqs.web.modules.uploader.FileStorageLocalProvider +import com.cubetiqs.web.modules.file.FileStorageFactory +import com.cubetiqs.web.modules.file.FileStorageLocalProvider import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Lazy import org.springframework.stereotype.Component diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileResponse.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileResponse.kt similarity index 73% rename from api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileResponse.kt rename to api/src/main/kotlin/com/cubetiqs/web/modules/file/FileResponse.kt index d555e8d..e4ea9ba 100644 --- a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileResponse.kt +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileResponse.kt @@ -1,4 +1,4 @@ -package com.cubetiqs.web.modules.uploader +package com.cubetiqs.web.modules.file import java.io.File diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageFactory.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageFactory.kt similarity index 76% rename from api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageFactory.kt rename to api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageFactory.kt index 32ca75f..eb13e18 100644 --- a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageFactory.kt +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageFactory.kt @@ -1,4 +1,4 @@ -package com.cubetiqs.web.modules.uploader +package com.cubetiqs.web.modules.file import org.springframework.web.multipart.MultipartFile import java.io.File @@ -7,7 +7,7 @@ object FileStorageFactory { private var provider: FileStorageProvider? = null fun setProvider(provider: FileStorageProvider) { - this.provider = provider + FileStorageFactory.provider = provider } fun getProvider(): FileStorageProvider { @@ -24,7 +24,7 @@ object FileStorageFactory { ) "C:\\Windows\\Temp" else "/tmp" val temp = File("$tempPath/${file.originalFilename}") file.transferTo(temp) - return this.store(temp) + return store(temp) } fun delete(fileName: String) { @@ -34,4 +34,12 @@ object FileStorageFactory { fun get(fileName: String): FileResponse { return getProvider().get(fileName) } + + fun zipAll(): ByteArray? { + if (getProvider() is FileStorageZipper) { + return (getProvider() as FileStorageZipper).zip(null) + } + + return null + } } \ No newline at end of file diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageLocalProvider.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageLocalProvider.kt similarity index 78% rename from api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageLocalProvider.kt rename to api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageLocalProvider.kt index c21b26a..34a88fd 100644 --- a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageLocalProvider.kt +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageLocalProvider.kt @@ -1,11 +1,12 @@ -package com.cubetiqs.web.modules.uploader +package com.cubetiqs.web.modules.file import java.io.File import java.io.FileNotFoundException +import java.io.OutputStream open class FileStorageLocalProvider( private val basePath: String, -) : FileStorageProvider { +) : FileStorageProvider, FileStorageZipper { private fun loadBasePath(fileName: String): String { val prefixPath = if (basePath.endsWith("/")) { "" @@ -51,4 +52,12 @@ open class FileStorageLocalProvider( throw IllegalArgumentException("File $fileName not found") } } + + override fun zip(sourceFolder: String?, os: OutputStream) { + FileZipper.zipToStream(sourceFolder ?: basePath, os) + } + + override fun zip(sourceFolder: String?): ByteArray { + return FileZipper.zipToBytes(sourceFolder ?: basePath) + } } \ No newline at end of file diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageProvider.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageProvider.kt similarity index 79% rename from api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageProvider.kt rename to api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageProvider.kt index 7d3da70..2ebc56b 100644 --- a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/FileStorageProvider.kt +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageProvider.kt @@ -1,4 +1,4 @@ -package com.cubetiqs.web.modules.uploader +package com.cubetiqs.web.modules.file import java.io.File diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageZipper.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageZipper.kt new file mode 100644 index 0000000..3f51987 --- /dev/null +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileStorageZipper.kt @@ -0,0 +1,13 @@ +package com.cubetiqs.web.modules.file + +import java.io.ByteArrayOutputStream +import java.io.OutputStream + +interface FileStorageZipper { + fun zip(sourceFolder: String?, os: OutputStream) + fun zip(sourceFolder: String?): ByteArray { + val os = ByteArrayOutputStream() + zip(sourceFolder, os) + return os.toByteArray() + } +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileZipper.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileZipper.kt new file mode 100644 index 0000000..dee9668 --- /dev/null +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/file/FileZipper.kt @@ -0,0 +1,58 @@ +package com.cubetiqs.web.modules.file + +import java.io.ByteArrayOutputStream +import java.io.FileOutputStream +import java.io.IOException +import java.io.OutputStream +import java.nio.file.* +import java.nio.file.attribute.BasicFileAttributes +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream + +object FileZipper { + fun zip(sourceFolder: String, destFolder: String) { + try { + val zipFolder = if (destFolder.endsWith(".zip")) { + "" + } else { + ".zip" + } + FileOutputStream(zipFolder).use { fos -> + zipToStream(sourceFolder, fos) + } + } catch (e: IOException) { + e.printStackTrace() + } + } + + fun zipToStream(sourceFolder: String, os: OutputStream) { + ZipOutputStream(os).use { zos -> + val sourcePath: Path = Paths.get(sourceFolder) + // Walk the tree structure using WalkFileTree method + Files.walkFileTree(sourcePath, object : SimpleFileVisitor() { + @Throws(IOException::class) + override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult { + if (sourcePath != dir) { + zos.putNextEntry(ZipEntry(sourcePath.relativize(dir).toString() + "/")) + zos.closeEntry() + } + return FileVisitResult.CONTINUE + } + + @Throws(IOException::class) + override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult { + zos.putNextEntry(ZipEntry(sourcePath.relativize(file).toString())) + Files.copy(file, zos) + zos.closeEntry() + return FileVisitResult.CONTINUE + } + }) + } + } + + fun zipToBytes(sourceFolder: String): ByteArray { + val bos = ByteArrayOutputStream() + zipToStream(sourceFolder, bos) + return bos.toByteArray() + } +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderController.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderController.kt index 3c97023..7a84a16 100644 --- a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderController.kt +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderController.kt @@ -1,5 +1,6 @@ package com.cubetiqs.web.modules.uploader +import com.cubetiqs.web.modules.file.FileStorageFactory import com.cubetiqs.web.util.RouteConstants import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter @@ -74,6 +75,20 @@ class UploaderController @Autowired constructor( FileCopyUtils.copy(file.readBytes(), response.outputStream) } + @ResponseStatus(value = org.springframework.http.HttpStatus.OK) + @GetMapping("/zip", produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) + @Operation(summary = "Zip all files") + fun zipAll( + response: HttpServletResponse, + ) { + val zipBytes = FileStorageFactory.zipAll() ?: throw IllegalArgumentException("Zip file not found") + response.setHeader("Content-Disposition", "attachment; filename=\"files.zip\"") + response.contentType = "application/zip" + response.setContentLengthLong(zipBytes.size.toLong()) + + FileCopyUtils.copy(zipBytes, response.outputStream) + } + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) @PostMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) @Operation(summary = "Upload a file") diff --git a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderEntity.kt b/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderEntity.kt index dcbb823..beaba44 100644 --- a/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderEntity.kt +++ b/api/src/main/kotlin/com/cubetiqs/web/modules/uploader/UploaderEntity.kt @@ -1,5 +1,6 @@ package com.cubetiqs.web.modules.uploader +import com.cubetiqs.web.modules.file.FileStorageFactory import com.fasterxml.jackson.annotation.JsonIgnore import org.hibernate.Hibernate import org.springframework.data.annotation.CreatedDate