diff --git a/Mock-Course-Re b/Mock-Course-Re index c98896a..00e51ce 160000 --- a/Mock-Course-Re +++ b/Mock-Course-Re @@ -1 +1 @@ -Subproject commit c98896a178068dba670620ba4e6a26bec81b5c31 +Subproject commit 00e51ce4fc522a9dc93913eca8691c8a7b8edbf8 diff --git a/src/main/kotlin/ch/uzh/ifi/access/service/CourseLifecycle.kt b/src/main/kotlin/ch/uzh/ifi/access/service/CourseLifecycle.kt index 3d7bc18..34275b9 100644 --- a/src/main/kotlin/ch/uzh/ifi/access/service/CourseLifecycle.kt +++ b/src/main/kotlin/ch/uzh/ifi/access/service/CourseLifecycle.kt @@ -123,6 +123,19 @@ class CourseLifecycle( task.files.forEach { file -> file.enabled = false } + // TODO: maybe do this in a less convoluted fashion + // reset all file attributes to false + taskDTO.files?.let { + (it.instruction + it.visible + it.grading + it.editable + it.solution).forEach { filePath -> + val file = createOrUpdateTaskFile(task, taskPath, filePath) + file.instruction = false + file.visible = false + file.grading = false + file.editable = false + file.solution = false + } + } + // set desired file attributes taskDTO.files?.instruction?.forEach { filePath -> createOrUpdateTaskFile(task, taskPath, filePath).instruction = true } diff --git a/src/main/kotlin/ch/uzh/ifi/access/service/CourseService.kt b/src/main/kotlin/ch/uzh/ifi/access/service/CourseService.kt index f78aafe..83cf1a9 100644 --- a/src/main/kotlin/ch/uzh/ifi/access/service/CourseService.kt +++ b/src/main/kotlin/ch/uzh/ifi/access/service/CourseService.kt @@ -287,6 +287,12 @@ class CourseService( .toList() } + fun getVisibleNonEditableFiles(taskId: Long?): List { + return taskFileRepository.findByTask_IdAndEnabledTrue(taskId) + .filter { file: TaskFile -> file.visible && !file.editable } + .toList() + } + private fun readLogsFile(path: Path): String { val logsFile = path.resolve("logs.txt").toFile() @@ -362,6 +368,31 @@ class CourseService( } dockerClient.createContainerCmd(it).use { containerCmd -> val submissionDir = workingDir.resolve("submissions").resolve(submission.id.toString()) + // add submission files (supplied by the frontend) + submission.files.forEach { file -> + file.taskFile?.path?.let { it1 -> // TODO: cleanup + file.content?.let { it2 -> + createLocalFile( + submissionDir, + it1, + it2 + ) + } + } + } + // add visible but not editable files (because these are not part of the submission files) + getVisibleNonEditableFiles(task.id) + .forEach(Consumer { file: TaskFile -> + file.path?.let { it1 -> // TODO: cleanup + file.template?.let { it2 -> + createLocalFile( + submissionDir, + it1, it2 + ) + } + } + }) + // add grading files if submission is graded if (submission.isGraded) { getGradingFiles(task.id) .forEach(Consumer { file: TaskFile -> @@ -383,18 +414,6 @@ class CourseService( } } } - submission.files.forEach { file -> - file.taskFile?.path?.let { it1 -> // TODO: cleanup - file.content?.let { it2 -> - createLocalFile( - submissionDir, - it1, - it2 - ) - } - } - } - // The student code is run on the tmpfs. // Main reason for this is that we have no other way of enforcing a disk quota. // TODO: make this size configurable in task config.toml? @@ -543,6 +562,12 @@ fi return courseLifecycle.updateFromRepository(existingCourse) } + @Transactional + fun updateCourseFromDirectory(courseSlug: String, directory: Path): Course { + val existingCourse = getCourseBySlug(courseSlug) + return courseLifecycle.updateFromDirectory(existingCourse, directory ) + } + @Transactional fun deleteCourse(courseSlug: String): Course { val existingCourse = getCourseBySlug(courseSlug) diff --git a/src/test/kotlin/ch/uzh/ifi/access/service/CourseLifecycleTests.kt b/src/test/kotlin/ch/uzh/ifi/access/service/CourseLifecycleTests.kt index 0c3b40e..37c38cf 100644 --- a/src/test/kotlin/ch/uzh/ifi/access/service/CourseLifecycleTests.kt +++ b/src/test/kotlin/ch/uzh/ifi/access/service/CourseLifecycleTests.kt @@ -51,6 +51,14 @@ class CourseLifecycleTests( courseService.getCourseBySlug("access-mock-course") } + @Test + @WithMockUser(username="supervisor@uzh.ch", authorities = ["supervisor"]) + @Order(0) + fun `Course update succeeds`() { + val absolutePath = Paths.get(File("Mock-Course-Re").absolutePath) + courseService.updateCourseFromDirectory("access-mock-course", absolutePath) + } + fun getCourse(): CourseWorkspace { return courseService.getCourseWorkspaceBySlug("access-mock-course") }