diff --git a/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/SubmissionStorage.kt b/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/SubmissionStorage.kt index 5fab964..1fb99da 100644 --- a/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/SubmissionStorage.kt +++ b/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/SubmissionStorage.kt @@ -43,16 +43,18 @@ class SubmissionStorage( return StoredSubmission(dir, names) } - /** Собирает zip из сохранённых файлов сдачи. */ + /** Собирает zip из сохранённых файлов сдачи, сохраняя реальное время изменения файлов. */ fun zipOf(storedDir: Path): ByteArray { val out = ByteArrayOutputStream() ZipOutputStream(out).use { zos -> - Files.list(storedDir).forEach { file -> - ZipEntry(file.fileName.toString()).also { entry -> - entry.time = 0 - zos.putNextEntry(entry) - Files.copy(file, zos) - zos.closeEntry() + Files.list(storedDir).use { stream -> + stream.forEach { file -> + ZipEntry(file.fileName.toString()).also { entry -> + entry.time = Files.getLastModifiedTime(file).toMillis() + zos.putNextEntry(entry) + Files.copy(file, zos) + zos.closeEntry() + } } } } diff --git a/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminSupport.kt b/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminSupport.kt index 44c7f61..4e7e2ba 100644 --- a/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminSupport.kt +++ b/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminSupport.kt @@ -23,6 +23,7 @@ import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.net.URLEncoder import java.nio.charset.StandardCharsets +import java.time.Instant import java.util.zip.ZipEntry import java.util.zip.ZipInputStream import java.util.zip.ZipOutputStream @@ -164,14 +165,14 @@ abstract class AdminSupport( ): ByteArray { val out = ByteArrayOutputStream() ZipOutputStream(out).use { zos -> - zos.putNextEntry(ZipEntry("ОПИСАНИЕ.txt").apply { time = 0 }) + zos.putNextEntry(ZipEntry("ОПИСАНИЕ.txt")) zos.write("Архив сдач группы $groupName (последние попытки)\n".toByteArray(Charsets.UTF_8)) zos.closeEntry() for (lab in labs) { for (sub in api.labSubmissions(token, lab.id)) { val student = studentById[sub.studentId] ?: continue val bytes = api.downloadSubmissionAsAdmin(token, sub.id).bytes - appendSubmissionArchive(zos, lab, student, bytes) + appendSubmissionArchive(zos, lab, student, bytes, sub.createdAt) } } } @@ -183,13 +184,21 @@ abstract class AdminSupport( lab: LabSummaryDto, student: StudentRowDto, submissionZip: ByteArray, + submissionCreatedAt: String? = null, ) { + val fallbackMillis = + submissionCreatedAt + ?.let { runCatching { Instant.parse(it).toEpochMilli() }.getOrNull() } + ?: System.currentTimeMillis() ZipInputStream(ByteArrayInputStream(submissionZip)).use { zin -> var entry = zin.nextEntry while (entry != null) { if (!entry.isDirectory) { val safeName = student.fullName.replace(Regex("[\\\\/:*?\"<>|]"), "_") - zos.putNextEntry(ZipEntry("ЛР${lab.number}/${student.studentNo}_$safeName/${entry.name}").apply { time = 0 }) + val entryMillis = entry.time.takeIf { it > 0 } ?: fallbackMillis + zos.putNextEntry( + ZipEntry("ЛР${lab.number}/${student.studentNo}_$safeName/${entry.name}").apply { time = entryMillis }, + ) zin.copyTo(zos) zos.closeEntry() }