-
Notifications
You must be signed in to change notification settings - Fork 0
feat(configuration): 파일 도메인 모델 및 규칙 정의 #26 #56
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
Merged
The head ref may contain hidden characters: "feat(document)-\uD30C\uC77C-\uB3C4\uBA54\uC778-\uBAA8\uB378-#26"
Merged
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
80b665a
feat(configuration): 파일 도메인 모델 및 형식 규칙 추가 #26
tlgms 49e3fc2
feat(configuration): 파일 도메인 예외 정의 #26
tlgms 194532a
feat(configuration): 파일 도메인 포트 및 커맨드 정의 #26
tlgms 6496df3
feat(configuration): 파일명 생성 규칙 및 키 조작 방어 추가 #26
tlgms eeddabd
test(configuration): 파일 도메인 규칙 테스트 추가 #26
tlgms 5aca244
fix(configuration): 저장 객체 키 랜덤 토큰을 32비트에서 128비트로 확장 #26
tlgms 42ebb0c
fix(configuration): object key 생성 시 파일명 안전성 검증 추가 #26
tlgms d61510a
refactor(configuration): 비상수 val 이름을 lowerCamelCase 로 변경 #26
tlgms File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
...ration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/DownloadUrl.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document | ||
|
|
||
| data class DownloadUrl( | ||
| val fileName: String, | ||
| val downloadUrl: String, | ||
| val expiresIn: Long, | ||
| ) |
25 changes: 25 additions & 0 deletions
25
...ation-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document | ||
|
|
||
| private const val MAX_DOCUMENT_SIZE_BYTES = 10L * 1024 * 1024 | ||
| private const val MAX_PHOTO_SIZE_BYTES = 5L * 1024 * 1024 | ||
| private const val MAX_ATTACHMENT_SIZE_BYTES = 20L * 1024 * 1024 | ||
|
|
||
| enum class FileCategory( | ||
| val prefix: String, | ||
| val allowedExtensions: Set<FileExtension>, | ||
| val maxSizeBytes: Long, | ||
| ) { | ||
| APPLICATION("application", FileExtension.DOCUMENT_FORMATS, MAX_DOCUMENT_SIZE_BYTES), | ||
| ADMISSION_TICKET("admission-ticket", FileExtension.DOCUMENT_FORMATS, MAX_DOCUMENT_SIZE_BYTES), | ||
| APPLICANT_LIST("applicant-list", setOf(FileExtension.XLSX), MAX_DOCUMENT_SIZE_BYTES), | ||
| PHOTO("photo", FileExtension.IMAGE_FORMATS, MAX_PHOTO_SIZE_BYTES), | ||
| ATTACHMENT("attachment", FileExtension.ATTACHMENT_FORMATS, MAX_ATTACHMENT_SIZE_BYTES), | ||
| GUIDELINE("guideline", FileExtension.ATTACHMENT_FORMATS, MAX_ATTACHMENT_SIZE_BYTES), | ||
| ; | ||
|
|
||
| fun supports(extension: FileExtension): Boolean = extension in allowedExtensions | ||
|
|
||
| fun exceedsMaxSize(sizeBytes: Long): Boolean = sizeBytes > maxSizeBytes | ||
|
|
||
| fun objectKeyOf(fileName: String): String = "$prefix/$fileName" | ||
| } | ||
17 changes: 17 additions & 0 deletions
17
...ation-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileDocument.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document | ||
|
|
||
| import java.time.Instant | ||
|
|
||
| data class FileDocument( | ||
| val id: Long? = null, | ||
| val originalName: String, | ||
| val objectKey: String, | ||
| val bucket: String, | ||
| val contentType: String, | ||
| val sizeBytes: Long, | ||
| val checksum: String, | ||
| val createdAt: Instant? = null, | ||
| ) { | ||
| val fileName: String | ||
| get() = objectKey.substringAfterLast('/') | ||
| } |
35 changes: 35 additions & 0 deletions
35
...tion-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileExtension.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document | ||
|
|
||
| enum class FileExtension( | ||
| val value: String, | ||
| val contentType: String, | ||
| private val aliases: Set<String> = emptySet(), | ||
| ) { | ||
| PDF("pdf", "application/pdf"), | ||
| HWP("hwp", "application/x-hwp"), | ||
| XLSX("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), | ||
| DOCX("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"), | ||
| JPG("jpg", "image/jpeg", setOf("jpeg")), | ||
| PNG("png", "image/png"), | ||
| WEBP("webp", "image/webp"), | ||
| ; | ||
|
|
||
| companion object { | ||
| val DOCUMENT_FORMATS = setOf(PDF, HWP) | ||
|
|
||
| val IMAGE_FORMATS = setOf(JPG, PNG, WEBP) | ||
|
|
||
| val ATTACHMENT_FORMATS = DOCUMENT_FORMATS + IMAGE_FORMATS + setOf(XLSX, DOCX) | ||
|
tlgms marked this conversation as resolved.
Outdated
|
||
|
|
||
| fun fromFileName(fileName: String): FileExtension? { | ||
| val extension = fileName.substringAfterLast('.', "") | ||
| if (extension.isEmpty()) return null | ||
| return fromExtension(extension) | ||
| } | ||
|
|
||
| fun fromExtension(extension: String): FileExtension? { | ||
| val normalized = extension.removePrefix(".").lowercase() | ||
| return entries.firstOrNull { it.value == normalized || normalized in it.aliases } | ||
| } | ||
| } | ||
| } | ||
51 changes: 51 additions & 0 deletions
51
...uration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileNaming.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.exception.InvalidFileNameException | ||
| import java.time.LocalDate | ||
| import java.time.format.DateTimeFormatter | ||
| import java.util.UUID | ||
|
|
||
| private val SAFE_IDENTIFIER = Regex("[A-Za-z0-9_-]+") | ||
| private val UNSAFE_CHARACTERS = Regex("[^A-Za-z0-9._-]") | ||
| private val APPLICANT_LIST_DATE = DateTimeFormatter.ofPattern("yyyyMMdd") | ||
|
|
||
| object FileNaming { | ||
|
|
||
| fun applicationFileName(receiptCode: String, extension: FileExtension): String = | ||
| "application_${requireIdentifier(receiptCode)}.${extension.value}" | ||
|
|
||
| fun admissionTicketFileName(receiptCode: String, extension: FileExtension): String = | ||
| "admission_ticket_${requireIdentifier(receiptCode)}.${extension.value}" | ||
|
|
||
| fun applicantListFileName(date: LocalDate): String = | ||
| "applicants_${APPLICANT_LIST_DATE.format(date)}.${FileExtension.XLSX.value}" | ||
|
|
||
| fun photoFileName(extension: FileExtension): String = | ||
| "photo_${randomToken()}.${extension.value}" | ||
|
|
||
| fun attachmentFileName(originalName: String): String = | ||
| "${randomToken()}_${sanitizeOriginalName(originalName)}" | ||
|
|
||
| fun requireIdentifier(value: String): String { | ||
| if (!SAFE_IDENTIFIER.matches(value)) throw InvalidFileNameException(value) | ||
| return value | ||
| } | ||
|
|
||
| fun requireSafeFileName(fileName: String): String { | ||
| if (sanitizeOriginalName(fileName) != fileName) throw InvalidFileNameException(fileName) | ||
| return fileName | ||
| } | ||
|
|
||
| fun sanitizeOriginalName(originalName: String): String { | ||
| val baseName = originalName | ||
| .substringAfterLast('/') | ||
| .substringAfterLast('\\') | ||
| .trim() | ||
| val sanitized = UNSAFE_CHARACTERS.replace(baseName, "_").trimStart('.') | ||
| if (sanitized.isEmpty() || sanitized == "_") throw InvalidFileNameException(originalName) | ||
| return sanitized | ||
| } | ||
|
|
||
| private fun randomToken(): String = | ||
| UUID.randomUUID().toString().replace("-", "") | ||
| } |
7 changes: 7 additions & 0 deletions
7
...ation-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/StoredObject.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document | ||
|
|
||
| data class StoredObject( | ||
| val bucket: String, | ||
| val objectKey: String, | ||
| val checksum: String, | ||
| ) |
8 changes: 8 additions & 0 deletions
8
...in/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.command | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.FileCategory | ||
|
|
||
| data class IssueDownloadUrlCommand( | ||
| val category: FileCategory, | ||
| val fileName: String, | ||
| ) |
10 changes: 10 additions & 0 deletions
10
...src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.command | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.FileCategory | ||
|
|
||
| data class UploadFileCommand( | ||
| val category: FileCategory, | ||
| val originalName: String, | ||
| val sizeBytes: Long, | ||
| val fileName: String? = null, | ||
| ) |
4 changes: 4 additions & 0 deletions
4
...n/hs/kr/entrydsm/configuration/domain/document/exception/FileDocumentNotFoundException.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.exception | ||
|
|
||
| class FileDocumentNotFoundException(objectKey: String) : | ||
| RuntimeException("File not found: $objectKey") |
4 changes: 4 additions & 0 deletions
4
...in/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileTooLargeException.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.exception | ||
|
|
||
| class FileTooLargeException(sizeBytes: Long, maxSizeBytes: Long) : | ||
| RuntimeException("File size $sizeBytes bytes exceeds limit of $maxSizeBytes bytes") |
9 changes: 9 additions & 0 deletions
9
...tlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileFormatException.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.exception | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.FileCategory | ||
|
|
||
| class InvalidFileFormatException(fileName: String, category: FileCategory) : | ||
| RuntimeException( | ||
| "Unsupported file format for ${category.name}: $fileName " + | ||
| "(allowed: ${category.allowedExtensions.joinToString { it.value }})" | ||
| ) |
4 changes: 4 additions & 0 deletions
4
...kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileNameException.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.exception | ||
|
|
||
| class InvalidFileNameException(fileName: String) : | ||
| RuntimeException("Invalid file name: $fileName") |
4 changes: 4 additions & 0 deletions
4
...n/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/PresignFailedException.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.exception | ||
|
|
||
| class PresignFailedException(objectKey: String, cause: Throwable? = null) : | ||
| RuntimeException("Failed to issue download URL: $objectKey", cause) |
4 changes: 4 additions & 0 deletions
4
...in/hs/kr/entrydsm/configuration/domain/document/exception/StorageUploadFailedException.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.exception | ||
|
|
||
| class StorageUploadFailedException(objectKey: String, cause: Throwable? = null) : | ||
| RuntimeException("Failed to upload file to storage: $objectKey", cause) |
9 changes: 9 additions & 0 deletions
9
...in/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/IssueDownloadUrlUseCase.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.port.`in` | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.DownloadUrl | ||
| import hs.kr.entrydsm.configuration.domain.document.command.IssueDownloadUrlCommand | ||
|
|
||
| interface IssueDownloadUrlUseCase { | ||
| fun issueByCommand(command: IssueDownloadUrlCommand): DownloadUrl | ||
| fun issueById(id: Long): DownloadUrl | ||
| } |
10 changes: 10 additions & 0 deletions
10
...n/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/ReadFileUseCase.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.port.`in` | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.FileCategory | ||
| import hs.kr.entrydsm.configuration.domain.document.FileDocument | ||
|
|
||
| interface ReadFileUseCase { | ||
| fun findById(id: Long): FileDocument | ||
| fun findByFileName(category: FileCategory, fileName: String): FileDocument? | ||
| fun existsById(id: Long): Boolean | ||
| } |
9 changes: 9 additions & 0 deletions
9
...src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/UploadFileUseCase.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.port.`in` | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.FileDocument | ||
| import hs.kr.entrydsm.configuration.domain.document.command.UploadFileCommand | ||
| import java.io.InputStream | ||
|
|
||
| interface UploadFileUseCase { | ||
| fun upload(command: UploadFileCommand, content: InputStream): FileDocument | ||
| } |
11 changes: 11 additions & 0 deletions
11
...in/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/FileDocumentRepository.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.port.out | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.FileDocument | ||
|
|
||
| interface FileDocumentRepository { | ||
| fun save(fileDocument: FileDocument): FileDocument | ||
| fun findById(id: Long): FileDocument? | ||
| fun findByObjectKey(objectKey: String): FileDocument? | ||
| fun existsById(id: Long): Boolean | ||
| fun deleteByObjectKey(objectKey: String) | ||
| } |
19 changes: 19 additions & 0 deletions
19
...main/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/StoragePort.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document.port.out | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.StoredObject | ||
| import java.io.InputStream | ||
|
|
||
| interface StoragePort { | ||
| fun upload( | ||
| objectKey: String, | ||
| contentType: String, | ||
| sizeBytes: Long, | ||
| content: InputStream, | ||
| ): StoredObject | ||
|
|
||
| fun issueDownloadUrl(objectKey: String, expiresInSeconds: Long): String | ||
|
|
||
| fun exists(objectKey: String): Boolean | ||
|
|
||
| fun delete(objectKey: String) | ||
| } |
100 changes: 100 additions & 0 deletions
100
...domain/src/test/kotlin/hs/kr/entrydsm/configuration/domain/document/DocumentDomainTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| package hs.kr.entrydsm.configuration.domain.document | ||
|
|
||
| import hs.kr.entrydsm.configuration.domain.document.exception.InvalidFileNameException | ||
| import org.junit.Assert.assertEquals | ||
| import org.junit.Assert.assertFalse | ||
| import org.junit.Assert.assertNull | ||
| import org.junit.Assert.assertTrue | ||
| import org.junit.Test | ||
| import java.time.LocalDate | ||
|
|
||
| class DocumentDomainTest { | ||
|
|
||
| @Test | ||
| fun `확장자를 대소문자 구분 없이 인식한다`() { | ||
| assertEquals(FileExtension.PDF, FileExtension.fromFileName("application_1001.PDF")) | ||
| assertEquals(FileExtension.XLSX, FileExtension.fromExtension(".xlsx")) | ||
| } | ||
|
|
||
| @Test | ||
| fun `jpeg는 jpg의 별칭으로 처리한다`() { | ||
| assertEquals(FileExtension.JPG, FileExtension.fromFileName("photo.jpeg")) | ||
| assertEquals("image/jpeg", FileExtension.JPG.contentType) | ||
| } | ||
|
|
||
| @Test | ||
| fun `확장자가 없으면 인식하지 않는다`() { | ||
| assertNull(FileExtension.fromFileName("noextension")) | ||
| assertNull(FileExtension.fromFileName("unknown.exe")) | ||
| } | ||
|
|
||
| @Test | ||
| fun `카테고리마다 허용 확장자가 다르다`() { | ||
| assertTrue(FileCategory.APPLICATION.supports(FileExtension.PDF)) | ||
| assertFalse(FileCategory.APPLICATION.supports(FileExtension.JPG)) | ||
| assertEquals(setOf(FileExtension.XLSX), FileCategory.APPLICANT_LIST.allowedExtensions) | ||
| assertTrue(FileCategory.PHOTO.supports(FileExtension.WEBP)) | ||
| assertFalse(FileCategory.PHOTO.supports(FileExtension.PDF)) | ||
| assertTrue(FileCategory.ATTACHMENT.supports(FileExtension.DOCX)) | ||
| } | ||
|
|
||
| @Test | ||
| fun `카테고리별 용량 한도를 넘으면 초과로 판정한다`() { | ||
| assertFalse(FileCategory.PHOTO.exceedsMaxSize(FileCategory.PHOTO.maxSizeBytes)) | ||
| assertTrue(FileCategory.PHOTO.exceedsMaxSize(FileCategory.PHOTO.maxSizeBytes + 1)) | ||
| } | ||
|
|
||
| @Test | ||
| fun `object key는 카테고리 prefix를 붙인다`() { | ||
| assertEquals( | ||
| "admission-ticket/admission_ticket_1001.pdf", | ||
| FileCategory.ADMISSION_TICKET.objectKeyOf("admission_ticket_1001.pdf"), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun `명세 예시와 같은 파일명을 만든다`() { | ||
| assertEquals( | ||
| "application_1001.pdf", | ||
| FileNaming.applicationFileName("1001", FileExtension.PDF), | ||
| ) | ||
| assertEquals( | ||
| "admission_ticket_1001.pdf", | ||
| FileNaming.admissionTicketFileName("1001", FileExtension.PDF), | ||
| ) | ||
| assertEquals( | ||
| "applicants_20260726.xlsx", | ||
| FileNaming.applicantListFileName(LocalDate.of(2026, 7, 26)), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun `증명사진과 첨부파일 이름에 랜덤 토큰을 붙인다`() { | ||
| assertTrue(FileNaming.photoFileName(FileExtension.JPG).matches(Regex("photo_[0-9a-f]{8}\\.jpg"))) | ||
| assertTrue(FileNaming.attachmentFileName("guide.pdf").matches(Regex("[0-9a-f]{8}_guide\\.pdf"))) | ||
| } | ||
|
|
||
| @Test | ||
| fun `원본 파일명에서 경로를 제거하고 허용 외 문자를 치환한다`() { | ||
| assertEquals("pas_swd.pdf", FileNaming.sanitizeOriginalName("../../etc/pas swd.pdf")) | ||
| assertEquals("report.xlsx", FileNaming.sanitizeOriginalName("C:\\temp\\report.xlsx")) | ||
| } | ||
|
|
||
| @Test(expected = InvalidFileNameException::class) | ||
| fun `수험번호에 경로 문자가 들어오면 거부한다`() { | ||
| FileNaming.requireIdentifier("../1001") | ||
| } | ||
|
|
||
| @Test(expected = InvalidFileNameException::class) | ||
| fun `다운로드 파일명에 상위 경로 참조가 들어오면 거부한다`() { | ||
| FileNaming.requireSafeFileName("../../etc/passwd") | ||
| } | ||
|
|
||
| @Test | ||
| fun `정상 다운로드 파일명은 그대로 통과시킨다`() { | ||
| assertEquals( | ||
| "applicants_20260726.xlsx", | ||
| FileNaming.requireSafeFileName("applicants_20260726.xlsx"), | ||
| ) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.