Skip to content

Commit

Permalink
Adaptive learning: Add weight to links between competencies and learn…
Browse files Browse the repository at this point in the history
…ing objects (#9517)
  • Loading branch information
JohannesStoehr authored Oct 30, 2024
1 parent ac4c2c1 commit d2fa064
Show file tree
Hide file tree
Showing 158 changed files with 1,504 additions and 999 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.util.Optional;
import java.util.Set;

import de.tum.cit.aet.artemis.atlas.domain.competency.CourseCompetency;
import de.tum.cit.aet.artemis.atlas.domain.competency.CompetencyLearningObjectLink;
import de.tum.cit.aet.artemis.core.domain.User;

public interface LearningObject {
Expand All @@ -19,7 +19,7 @@ public interface LearningObject {

Long getId();

Set<CourseCompetency> getCompetencies();
Set<? extends CompetencyLearningObjectLink> getCompetencyLinks();

boolean isVisibleToStudents();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package de.tum.cit.aet.artemis.atlas.domain.competency;

import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import com.fasterxml.jackson.annotation.JsonIgnore;

import de.tum.cit.aet.artemis.exercise.domain.Exercise;

@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "competency_exercise")
public class CompetencyExerciseLink extends CompetencyLearningObjectLink {

@EmbeddedId
@JsonIgnore
protected CompetencyExerciseId id = new CompetencyExerciseId();

@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@MapsId("exerciseId")
private Exercise exercise;

public CompetencyExerciseLink(CourseCompetency competency, Exercise exercise, double weight) {
super(competency, weight);
this.exercise = exercise;
}

public CompetencyExerciseLink() {
// Empty constructor for Spring
}

public Exercise getExercise() {
return exercise;
}

public void setExercise(Exercise exercise) {
this.exercise = exercise;
}

public CompetencyExerciseId getId() {
return id;
}

@Override
public String toString() {
return "CompetencyExerciseLink{" + "exercise=" + exercise + ", id=" + id + ", competency=" + competency + ", weight=" + weight + '}';
}

@Embeddable
public static class CompetencyExerciseId implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

private long exerciseId;

private long competencyId;

public CompetencyExerciseId() {
// Empty constructor for Spring
}

public CompetencyExerciseId(long exerciseId, long competencyId) {
this.exerciseId = exerciseId;
this.competencyId = competencyId;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CompetencyExerciseId that)) {
return false;
}
return exerciseId == that.exerciseId && competencyId == that.competencyId;
}

@Override
public int hashCode() {
return Objects.hash(exerciseId, competencyId);
}

@Override
public String toString() {
return "CompetencyExerciseId{" + "exerciseId=" + exerciseId + ", competencyId=" + competencyId + '}';
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package de.tum.cit.aet.artemis.atlas.domain.competency;

import java.io.Serializable;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.MapsId;

@MappedSuperclass
public abstract class CompetencyLearningObjectLink implements Serializable {

@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@MapsId("competencyId")
protected CourseCompetency competency;

@Column(name = "link_weight")
protected double weight;

public CompetencyLearningObjectLink(CourseCompetency competency, double weight) {
this.competency = competency;
this.weight = weight;
}

public CompetencyLearningObjectLink() {
// Empty constructor for Spring
}

public CourseCompetency getCompetency() {
return competency;
}

public void setCompetency(CourseCompetency competency) {
this.competency = competency;
}

public double getWeight() {
return weight;
}

public void setWeight(double weight) {
this.weight = weight;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package de.tum.cit.aet.artemis.atlas.domain.competency;

import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import com.fasterxml.jackson.annotation.JsonIgnore;

import de.tum.cit.aet.artemis.lecture.domain.LectureUnit;

@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "competency_lecture_unit")
public class CompetencyLectureUnitLink extends CompetencyLearningObjectLink {

@EmbeddedId
@JsonIgnore
protected CompetencyLectureUnitId id = new CompetencyLectureUnitId();

@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
@MapsId("lectureUnitId")
private LectureUnit lectureUnit;

public CompetencyLectureUnitLink(CourseCompetency competency, LectureUnit lectureUnit, double weight) {
super(competency, weight);
this.lectureUnit = lectureUnit;
}

public CompetencyLectureUnitLink() {
// Empty constructor for Spring
}

public LectureUnit getLectureUnit() {
return lectureUnit;
}

public void setLectureUnit(LectureUnit lectureUnit) {
this.lectureUnit = lectureUnit;
}

public CompetencyLectureUnitId getId() {
return id;
}

@Override
public String toString() {
return "CompetencyLectureUnitLink{" + "lectureUnit=" + lectureUnit + ", id=" + id + ", competency=" + competency + ", weight=" + weight + '}';
}

@Embeddable
public static class CompetencyLectureUnitId implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

private long lectureUnitId;

private long competencyId;

public CompetencyLectureUnitId() {
// Empty constructor for Spring
}

public CompetencyLectureUnitId(long lectureUnitId, long competencyId) {
this.lectureUnitId = lectureUnitId;
this.competencyId = competencyId;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CompetencyLectureUnitId that)) {
return false;
}
return lectureUnitId == that.lectureUnitId && competencyId == that.competencyId;
}

@Override
public int hashCode() {
return Objects.hash(lectureUnitId, competencyId);
}

@Override
public String toString() {
return "CompetencyLectureUnitId{" + "lectureUnitId=" + lectureUnitId + ", competencyId=" + competencyId + '}';
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import de.tum.cit.aet.artemis.core.domain.Course;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
import de.tum.cit.aet.artemis.lecture.domain.ExerciseUnit;
import de.tum.cit.aet.artemis.lecture.domain.LectureUnit;

/**
* CourseCompetency is an abstract class for all competency types that are part of a course.
Expand Down Expand Up @@ -71,13 +69,13 @@ public abstract class CourseCompetency extends BaseCompetency {
@JsonIgnoreProperties({ "competencies" })
private StandardizedCompetency linkedStandardizedCompetency;

@ManyToMany(mappedBy = "competencies")
@JsonIgnoreProperties({ "competencies", "course" })
private Set<Exercise> exercises = new HashSet<>();
@OneToMany(mappedBy = "competency", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnoreProperties("competency")
private Set<CompetencyExerciseLink> exerciseLinks = new HashSet<>();

@ManyToMany(mappedBy = "competencies")
@JsonIgnoreProperties("competencies")
private Set<LectureUnit> lectureUnits = new HashSet<>();
@OneToMany(mappedBy = "competency", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnoreProperties("competency")
private Set<CompetencyLectureUnitLink> lectureUnitLinks = new HashSet<>();

@OneToMany(mappedBy = "competency", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, orphanRemoval = true)
@JsonIgnoreProperties({ "user", "competency" })
Expand Down Expand Up @@ -161,55 +159,20 @@ public void setLinkedStandardizedCompetency(StandardizedCompetency linkedStandar
this.linkedStandardizedCompetency = linkedStandardizedCompetency;
}

public Set<Exercise> getExercises() {
return exercises;
}

public void setExercises(Set<Exercise> exercises) {
this.exercises = exercises;
public Set<CompetencyExerciseLink> getExerciseLinks() {
return exerciseLinks;
}

public void addExercise(Exercise exercise) {
this.exercises.add(exercise);
exercise.getCompetencies().add(this);
public void setExerciseLinks(Set<CompetencyExerciseLink> exerciseLinks) {
this.exerciseLinks = exerciseLinks;
}

public Set<LectureUnit> getLectureUnits() {
return lectureUnits;
public Set<CompetencyLectureUnitLink> getLectureUnitLinks() {
return lectureUnitLinks;
}

public void setLectureUnits(Set<LectureUnit> lectureUnits) {
this.lectureUnits = lectureUnits;
}

/**
* Adds the lecture unit to the competency (bidirectional)
* Note: ExerciseUnits are not accepted, should be set via the connected exercise (see {@link #addExercise(Exercise)})
*
* @param lectureUnit The lecture unit to add
*/
public void addLectureUnit(LectureUnit lectureUnit) {
if (lectureUnit instanceof ExerciseUnit) {
// The competencies of ExerciseUnits are taken from the corresponding exercise
throw new IllegalArgumentException("ExerciseUnits can not be connected to competencies");
}
this.lectureUnits.add(lectureUnit);
lectureUnit.getCompetencies().add(this);
}

/**
* Removes the lecture unit from the competency (bidirectional)
* Note: ExerciseUnits are not accepted, should be set via the connected exercise
*
* @param lectureUnit The lecture unit to remove
*/
public void removeLectureUnit(LectureUnit lectureUnit) {
if (lectureUnit instanceof ExerciseUnit) {
// The competencies of ExerciseUnits are taken from the corresponding exercise
throw new IllegalArgumentException("ExerciseUnits can not be disconnected from competencies");
}
this.lectureUnits.remove(lectureUnit);
lectureUnit.getCompetencies().remove(this);
public void setLectureUnitLinks(Set<CompetencyLectureUnitLink> lectureUnitLinks) {
this.lectureUnitLinks = lectureUnitLinks;
}

public Set<CompetencyProgress> getUserProgress() {
Expand All @@ -234,6 +197,6 @@ public void setLearningPaths(Set<LearningPath> learningPaths) {
@PrePersist
@PreUpdate
public void prePersistOrUpdate() {
this.lectureUnits.removeIf(lectureUnit -> lectureUnit instanceof ExerciseUnit);
this.lectureUnitLinks.removeIf(lectureUnit -> lectureUnit.getLectureUnit() instanceof ExerciseUnit);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package de.tum.cit.aet.artemis.atlas.repository;

import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;

import de.tum.cit.aet.artemis.atlas.domain.competency.CompetencyExerciseLink;
import de.tum.cit.aet.artemis.core.repository.base.ArtemisJpaRepository;

@Profile(PROFILE_CORE)
@Repository
public interface CompetencyExerciseLinkRepository extends ArtemisJpaRepository<CompetencyExerciseLink, Long> {

}
Loading

0 comments on commit d2fa064

Please sign in to comment.