Skip to content

Commit

Permalink
Implement persistent result files
Browse files Browse the repository at this point in the history
  • Loading branch information
sealexan committed Jan 22, 2024
1 parent 60a7a8e commit 1a1c3b4
Show file tree
Hide file tree
Showing 28 changed files with 219 additions and 76 deletions.
1 change: 0 additions & 1 deletion src/main/kotlin/ch/uzh/ifi/access/AccessApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package ch.uzh.ifi.access
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.cache.annotation.EnableCaching


@SpringBootApplication
Expand Down
2 changes: 0 additions & 2 deletions src/main/kotlin/ch/uzh/ifi/access/config/SecurityConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import io.github.oshai.kotlinlogging.KotlinLogging
import lombok.AllArgsConstructor
import org.keycloak.admin.client.Keycloak
import org.keycloak.admin.client.resource.RealmResource
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
Expand All @@ -24,7 +23,6 @@ import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
import org.springframework.security.web.session.HttpSessionEventPublisher
import org.springframework.stereotype.Component
import org.springframework.web.filter.CommonsRequestLoggingFilter
import java.nio.file.Path
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/ch/uzh/ifi/access/model/GlobalFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class GlobalFile {
@Column(nullable = false, columnDefinition = "text")
var template: String? = null

@Column(nullable=true, name="template_binary", columnDefinition="bytea")
@Column(nullable=true, columnDefinition="bytea")
var templateBinary: ByteArray? = null

val binary: Boolean
Expand Down
33 changes: 33 additions & 0 deletions src/main/kotlin/ch/uzh/ifi/access/model/ResultFile.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ch.uzh.ifi.access.model

import com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.*


@Entity
class ResultFile {
@Id
@GeneratedValue
var id: Long? = null

@Column(nullable = false)
var path: String? = null

@JsonIgnore
@ManyToOne
@JoinColumn(nullable = false, name = "submission_id")
var submission: Submission? = null

@Column(nullable = false)
var mimeType: String? = null

@Column(nullable=true, columnDefinition="text")
var content: String? = null

@Column(nullable=true, columnDefinition="bytea")
var contentBinary: ByteArray? = null

val binary: Boolean
get() = contentBinary != null

}
14 changes: 3 additions & 11 deletions src/main/kotlin/ch/uzh/ifi/access/model/Submission.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package ch.uzh.ifi.access.model

import ch.uzh.ifi.access.model.constants.Command
import ch.uzh.ifi.access.model.dao.Results
import com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.*
import lombok.Getter
import lombok.Setter
import org.apache.commons.lang3.StringUtils
import org.hibernate.annotations.CreationTimestamp
import java.time.LocalDateTime
import java.util.*

@Getter
@Setter
Expand Down Expand Up @@ -45,6 +43,9 @@ class Submission {
@OneToMany(mappedBy = "submission", cascade = [CascadeType.ALL])
var files: MutableList<SubmissionFile> = ArrayList()

@OneToMany(mappedBy = "submission", cascade = [CascadeType.ALL])
var persistentResultFiles: MutableList<ResultFile> = ArrayList()

@JsonIgnore
@ManyToOne
@JoinColumn(nullable = false, name = "evaluation_id")
Expand All @@ -56,13 +57,4 @@ class Submission {
val isGraded: Boolean
get() = command!!.isGraded

fun parseResults(results: Results) {
output = results.hints?.filterNotNull()?.firstOrNull()
if (results.points != null) {
valid = true
// never go over 100%; the number of points is otherwise up to the test suite to determine correctly
points = minOf(results.points!!, maxPoints!!)
evaluation!!.update(points)
}
}
}
5 changes: 5 additions & 0 deletions src/main/kotlin/ch/uzh/ifi/access/model/Task.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package ch.uzh.ifi.access.model

import ch.uzh.ifi.access.model.constants.Command
import jakarta.persistence.*
import org.hibernate.annotations.JdbcTypeCode
import org.hibernate.type.SqlTypes
import java.time.Duration
import java.util.*

Expand Down Expand Up @@ -55,6 +57,9 @@ class Task {
@OneToMany(mappedBy = "task", cascade = [CascadeType.ALL])
var files: MutableList<TaskFile> = ArrayList()

@JdbcTypeCode(SqlTypes.JSON)
var persistentResultFilePaths: MutableList<String> = ArrayList()

@OneToMany(mappedBy = "task", cascade = [CascadeType.ALL])
var evaluations: MutableList<Evaluation> = ArrayList()

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/ch/uzh/ifi/access/model/TaskFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class TaskFile {
@Column(nullable=true, columnDefinition="text")
var template: String? = null

@Column(nullable=true, name="template_binary", columnDefinition="bytea")
@Column(nullable=true, columnDefinition="bytea")
var templateBinary: ByteArray? = null

val binary: Boolean
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/ch/uzh/ifi/access/model/dao/Results.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import lombok.Data
@Data
class Results(
var points: Double? = null,
var hints: List<String>? = null
var hints: MutableList<String> = mutableListOf()
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package ch.uzh.ifi.access.model.dto

import ch.uzh.ifi.access.model.AssignmentInformation
import ch.uzh.ifi.access.projections.AssignmentInformationPublic
import com.fasterxml.jackson.annotation.JsonInclude

@JsonInclude(JsonInclude.Include.NON_EMPTY)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package ch.uzh.ifi.access.model.dto

import ch.uzh.ifi.access.projections.CourseInformationPublic


class CourseProgressDTO (
val userId: String? = null,
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/ch/uzh/ifi/access/model/dto/TaskFilesDTO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class TaskFilesDTO(
var visible: List<String> = ArrayList(),
var editable: List<String> = ArrayList(),
var grading: List<String> = ArrayList(),
var solution: List<String> = ArrayList()
var solution: List<String> = ArrayList(),
var persist: List<String> = ArrayList()
)

class CourseFilesDTO : TaskFilesDTO()
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.uzh.ifi.access.projections

import ch.uzh.ifi.access.model.*
import ch.uzh.ifi.access.model.Assignment
import ch.uzh.ifi.access.model.AssignmentInformation
import ch.uzh.ifi.access.model.dao.Timer
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.rest.core.config.Projection
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.uzh.ifi.access.projections

import ch.uzh.ifi.access.model.*
import ch.uzh.ifi.access.model.Assignment
import ch.uzh.ifi.access.model.AssignmentInformation
import ch.uzh.ifi.access.model.dao.Timer
import com.fasterxml.jackson.annotation.JsonFormat
import org.springframework.beans.factory.annotation.Value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ interface SubmissionSummary {
val output: String?
val createdAt: LocalDateTime?
val files: List<Any?>?
val persistentResultFiles: List<Any?>?
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.uzh.ifi.access.projections

import ch.uzh.ifi.access.model.*
import ch.uzh.ifi.access.model.Task
import ch.uzh.ifi.access.model.TaskInformation
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.rest.core.config.Projection

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import ch.uzh.ifi.access.projections.AssignmentWorkspace
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.security.access.prepost.PostAuthorize
import org.springframework.security.access.prepost.PostFilter
import java.util.*

interface AssignmentRepository : JpaRepository<Assignment?, Long?> {
@PostFilter("filterObject.enabled and (hasRole(#courseSlug + '-assistant') or (hasRole(#courseSlug) and filterObject.isPublished) or hasRole(#courseSlug + '-supervisor'))")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import ch.uzh.ifi.access.projections.MemberOverview
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.security.access.prepost.PostFilter
import java.util.*

interface CourseRepository : JpaRepository<Course?, Long?> {
fun getBySlug(courseSlug: String?): Course?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import ch.uzh.ifi.access.model.dao.Rank
import ch.uzh.ifi.access.projections.EvaluationSummary
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import java.util.*


interface EvaluationRepository : JpaRepository<Evaluation?, Long?> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import ch.uzh.ifi.access.model.TaskFile
import jakarta.transaction.Transactional
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.security.access.prepost.PostFilter
import java.util.*

interface TaskFileRepository : JpaRepository<TaskFile?, Long?> {
@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import ch.uzh.ifi.access.model.Task
import ch.uzh.ifi.access.projections.TaskWorkspace
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.security.access.prepost.PostAuthorize
import java.util.*

interface TaskRepository : JpaRepository<Task?, Long?> {
// TODO: visibility based on date
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import ch.uzh.ifi.access.model.dto.*
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.node.NullNode
import com.fasterxml.jackson.dataformat.toml.TomlMapper
import org.apache.commons.compress.utils.FileNameUtils
import org.springframework.stereotype.Service
import java.nio.file.Files
import java.nio.file.Path
Expand Down Expand Up @@ -129,6 +128,7 @@ class CourseConfigImporter(
"editable" -> files.editable = filenames
"grading" -> files.grading = filenames
"solution" -> files.solution = filenames
"persist" -> files.persist = filenames
}
}
task.files = files
Expand Down
26 changes: 15 additions & 11 deletions src/main/kotlin/ch/uzh/ifi/access/service/CourseLifecycle.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CourseLifecycle(
private val workingDir: Path,
private val roleService: RoleService,
private val courseRepository: CourseRepository,
// private val persistentResultFilePathRepository: PersistentResultFilePathRepository,
private val modelMapper: ModelMapper,
private val dockerClient: DockerClient,
private val cci: CourseConfigImporter,
Expand Down Expand Up @@ -153,6 +154,11 @@ class CourseLifecycle(
taskDTO.files?.solution?.forEach { filePath ->
createOrUpdateTaskFile( task, taskPath, filePath ).solution = true
}
// update persistent file paths
task.persistentResultFilePaths.clear()
taskDTO.files?.persist?.forEach { path ->
task.persistentResultFilePaths.add(path)
}
}
//assignment.setMaxPoints(assignment.getTasks().stream().filter(Task::enabled).mapToDouble(Task::getMaxPoints).sum());
//assignment.maxPoints = assignment.tasks.map { it.maxPoints!! }.sum() // TODO: safety
Expand All @@ -169,12 +175,11 @@ class CourseLifecycle(
.filter { existing: TaskFile -> existing.path == rootedFilePath }.findFirst()
.orElseGet { task.createFile() }
val taskFilePath = parentPath.resolve(unrootedFilePath)
val taskFileDTO = fileService.storeFile(taskFilePath, TaskFileDTO())
modelMapper.map(taskFileDTO, taskFile)
taskFile.name = taskFilePath.fileName.toString()
taskFile.path = rootedFilePath
taskFile.enabled = true
return taskFile
val taskFileUpdated = fileService.storeFile(taskFilePath, taskFile)
taskFileUpdated.name = taskFilePath.fileName.toString()
taskFileUpdated.path = rootedFilePath
taskFileUpdated.enabled = true
return taskFileUpdated
}

private fun createOrUpdateGlobalFile(course: Course, parentPath: Path, path: String): GlobalFile {
Expand All @@ -184,11 +189,10 @@ class CourseLifecycle(
.filter { existing -> existing.path == rootedFilePath }.findFirst()
.orElseGet { course.createFile() }
val globalFilePath = parentPath.resolve(unrootedFilePath)
val globalFileDTO = fileService.storeFile(globalFilePath, TaskFileDTO())
modelMapper.map(globalFileDTO, globalFile)
globalFile.name = globalFilePath.fileName.toString()
globalFile.path = rootedFilePath
globalFile.enabled = true
val globalFileUpdated = fileService.storeFile(globalFilePath, globalFile)
globalFileUpdated.name = globalFilePath.fileName.toString()
globalFileUpdated.path = rootedFilePath
globalFileUpdated.enabled = true
return globalFile
}

Expand Down
Loading

0 comments on commit 1a1c3b4

Please sign in to comment.