Skip to content
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

Adaptive learning: Change mastery threshold to input field and validate values #9398

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.Set;

import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.BadRequestException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -136,9 +135,8 @@ public ResponseEntity<Competency> getCompetency(@PathVariable long competencyId,
@EnforceAtLeastInstructorInCourse
public ResponseEntity<Competency> createCompetency(@PathVariable long courseId, @RequestBody Competency competency) throws URISyntaxException {
log.debug("REST request to create Competency : {}", competency);
if (competency.getId() != null || competency.getTitle() == null || competency.getTitle().trim().isEmpty()) {
throw new BadRequestException();
}
checkCompetencyAttributesForCreation(competency);

JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
var course = courseRepository.findWithEagerCompetenciesAndPrerequisitesByIdElseThrow(courseId);

final var persistedCompetency = competencyService.createCourseCompetency(competency, course);
Expand All @@ -159,9 +157,7 @@ public ResponseEntity<Competency> createCompetency(@PathVariable long courseId,
public ResponseEntity<List<Competency>> createCompetencies(@PathVariable Long courseId, @RequestBody List<Competency> competencies) throws URISyntaxException {
log.debug("REST request to create Competencies : {}", competencies);
for (Competency competency : competencies) {
if (competency.getId() != null || competency.getTitle() == null || competency.getTitle().trim().isEmpty()) {
throw new BadRequestException();
}
checkCompetencyAttributesForCreation(competency);
}
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
var course = courseRepository.findWithEagerCompetenciesAndPrerequisitesByIdElseThrow(courseId);

Expand Down Expand Up @@ -300,9 +296,8 @@ public ResponseEntity<List<CompetencyImportResponseDTO>> importStandardizedCompe
@EnforceAtLeastInstructorInCourse
public ResponseEntity<Competency> updateCompetency(@PathVariable long courseId, @RequestBody Competency competency) {
log.debug("REST request to update Competency : {}", competency);
if (competency.getId() == null) {
throw new BadRequestException();
}
checkCompetencyAttributesForUpdate(competency);

JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
var course = courseRepository.findByIdElseThrow(courseId);
var existingCompetency = competencyRepository.findByIdWithLectureUnitsElseThrow(competency.getId());
checkCourseForCompetency(course, existingCompetency);
Expand Down Expand Up @@ -334,6 +329,26 @@ public ResponseEntity<Void> deleteCompetency(@PathVariable long competencyId, @P
return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, competency.getTitle())).build();
}

private void checkCompetencyAttributesForCreation(Competency competency) {
if (competency.getId() != null) {
throw new BadRequestAlertException("A new competency should not have an id", ENTITY_NAME, "existingCompetencyId");
}
checkCompetencyAttributes(competency);
}

private void checkCompetencyAttributesForUpdate(Competency competency) {
if (competency.getId() == null) {
throw new BadRequestAlertException("An updated competency should have an id", ENTITY_NAME, "missingCompetencyId");
}
checkCompetencyAttributes(competency);
}
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved

private void checkCompetencyAttributes(Competency competency) {
if (competency.getTitle() == null || competency.getTitle().trim().isEmpty() || competency.getMasteryThreshold() < 1 || competency.getMasteryThreshold() > 100) {
throw new BadRequestAlertException("The attributes of the competency are invalid!", ENTITY_NAME, "invalidPrerequisiteAttributes");
}
}
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved

/**
* Checks if the competency matches the course.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.Set;

import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.BadRequestException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -139,9 +138,8 @@ public ResponseEntity<Prerequisite> getPrerequisite(@PathVariable long prerequis
@EnforceAtLeastInstructorInCourse
public ResponseEntity<Prerequisite> createPrerequisite(@PathVariable long courseId, @RequestBody Prerequisite prerequisite) throws URISyntaxException {
log.debug("REST request to create Prerequisite : {}", prerequisite);
if (prerequisite.getId() != null || prerequisite.getTitle() == null || prerequisite.getTitle().trim().isEmpty()) {
throw new BadRequestException();
}
checkPrerequisitesAttributesForCreation(prerequisite);

JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
var course = courseRepository.findWithEagerCompetenciesAndPrerequisitesByIdElseThrow(courseId);

final var persistedPrerequisite = prerequisiteService.createCourseCompetency(prerequisite, course);
Expand All @@ -162,9 +160,7 @@ public ResponseEntity<Prerequisite> createPrerequisite(@PathVariable long course
public ResponseEntity<List<Prerequisite>> createPrerequisite(@PathVariable Long courseId, @RequestBody List<Prerequisite> prerequisites) throws URISyntaxException {
log.debug("REST request to create Prerequisites : {}", prerequisites);
for (Prerequisite prerequisite : prerequisites) {
if (prerequisite.getId() != null || prerequisite.getTitle() == null || prerequisite.getTitle().trim().isEmpty()) {
throw new BadRequestException();
}
checkPrerequisitesAttributesForCreation(prerequisite);
}
var course = courseRepository.findWithEagerCompetenciesAndPrerequisitesByIdElseThrow(courseId);

Expand Down Expand Up @@ -303,9 +299,8 @@ public ResponseEntity<List<CompetencyImportResponseDTO>> importStandardizedPrere
@EnforceAtLeastInstructorInCourse
public ResponseEntity<Prerequisite> updatePrerequisite(@PathVariable long courseId, @RequestBody Prerequisite prerequisite) {
log.debug("REST request to update Prerequisite : {}", prerequisite);
if (prerequisite.getId() == null) {
throw new BadRequestException();
}
checkPrerequisitesAttributesForUpdate(prerequisite);

var course = courseRepository.findByIdElseThrow(courseId);
var existingPrerequisite = prerequisiteRepository.findByIdWithLectureUnitsElseThrow(prerequisite.getId());
checkCourseForPrerequisite(course, existingPrerequisite);
Expand Down Expand Up @@ -337,6 +332,26 @@ public ResponseEntity<Void> deletePrerequisite(@PathVariable long prerequisiteId
return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, prerequisite.getTitle())).build();
}

private void checkPrerequisitesAttributesForCreation(Prerequisite prerequisite) {
if (prerequisite.getId() != null) {
throw new BadRequestAlertException("A new prerequiste should not have an id", ENTITY_NAME, "existingPrerequisiteId");
}
checkPrerequisitesAttributes(prerequisite);
}

private void checkPrerequisitesAttributesForUpdate(Prerequisite prerequisite) {
if (prerequisite.getId() == null) {
throw new BadRequestAlertException("An updated prerequiste should have an id", ENTITY_NAME, "missingPrerequisiteId");
}
checkPrerequisitesAttributes(prerequisite);
}

private void checkPrerequisitesAttributes(Prerequisite prerequisite) {
if (prerequisite.getTitle() == null || prerequisite.getTitle().trim().isEmpty() || prerequisite.getMasteryThreshold() < 1 || prerequisite.getMasteryThreshold() > 100) {
throw new BadRequestAlertException("The attributes of the competency are invalid!", ENTITY_NAME, "invalidPrerequisiteAttributes");
}
}
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved

/**
* Checks if the prerequisite matches the course.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
<small> ({{ 'artemisApp.courseCompetency.create.averageMastery' | artemisTranslate }}: {{ averageStudentScore }}%) </small>
}
</label>
<input type="range" min="0" max="100" class="form-range" id="masteryThreshold" formControlName="masteryThreshold" />
<input required type="number" class="form-control" name="masteryThreshold" id="masteryThreshold" min="1" max="100" formControlName="masteryThreshold" />
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
</div>
}
<div class="form-group">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ void shouldUpdateCompetencyToOptionalWhenSettingOptional(CourseCompetency newCom
newCompetency.setTitle("Title");
newCompetency.setDescription("Description");
newCompetency.setCourse(course);
newCompetency.setMasteryThreshold(42);
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
newCompetency = courseCompetencyRepository.save(newCompetency);

TextExercise exercise = TextExerciseFactory.generateTextExercise(ZonedDateTime.now(), ZonedDateTime.now(), ZonedDateTime.now(), course);
Expand All @@ -355,6 +356,7 @@ void shouldCreateValidCompetency(CourseCompetency newCompetency) throws Exceptio
newCompetency.setTitle("FreshlyCreatedCompetency");
newCompetency.setDescription("This is an example of a freshly created competency");
newCompetency.setCourse(course);
newCompetency.setMasteryThreshold(42);
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
List<LectureUnit> allLectureUnits = lectureUnitRepository.findAll();
Set<LectureUnit> connectedLectureUnits = new HashSet<>(allLectureUnits);
newCompetency.setLectureUnits(connectedLectureUnits);
Expand Down Expand Up @@ -419,10 +421,12 @@ void shouldCreateCompetencies(CourseCompetency competency1, CourseCompetency com
competency1.setDescription("This is an example competency");
competency1.setTaxonomy(CompetencyTaxonomy.UNDERSTAND);
competency1.setCourse(course);
competency1.setMasteryThreshold(42);
competency2.setTitle("Competency2");
competency2.setDescription("This is another example competency");
competency2.setTaxonomy(CompetencyTaxonomy.REMEMBER);
competency2.setCourse(course);
competency2.setMasteryThreshold(84);
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved

var competenciesToCreate = List.of(competency1, competency2);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ private Competency createCompetency(Course course, String suffix) {
competency.setDescription("Magna pars studiorum, prodita quaerimus.");
competency.setTaxonomy(CompetencyTaxonomy.UNDERSTAND);
competency.setCourse(course);
competency.setMasteryThreshold(42);
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved

return competencyRepo.save(competency);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public Prerequisite createPrerequisite(Course course) {
prerequisite.setTitle("Example Prerequisite");
prerequisite.setDescription("Magna pars studiorum, prodita quaerimus.");
prerequisite.setCourse(course);
prerequisite.setMasteryThreshold(42);
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
return prerequisiteRepository.save(prerequisite);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
competencyToCreate.setTitle("CompetencyToCreateTitle");
competencyToCreate.setCourse(course);
competencyToCreate.setLectureUnits(Set.of(textUnit));
competencyToCreate.setMasteryThreshold(42);
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
JohannesStoehr marked this conversation as resolved.
Show resolved Hide resolved
return request.postWithResponseBody("/api/courses/" + course.getId() + "/competencies", competencyToCreate, Competency.class, HttpStatus.CREATED);
}

Expand Down Expand Up @@ -414,7 +415,7 @@

final var student = userTestRepository.findOneByLogin(STUDENT_OF_COURSE).orElseThrow();
var learningPath = learningPathRepository.findWithEagerCompetenciesByCourseIdAndUserIdElseThrow(course.getId(), student.getId());
assertThat(learningPath.getProgress()).as("contains no completed competency").isEqualTo(0);

Check failure on line 418 in src/test/java/de/tum/cit/aet/artemis/atlas/learningpath/LearningPathIntegrationTest.java

View workflow job for this annotation

GitHub Actions / H2 Tests

de.tum.cit.aet.artemis.atlas.learningpath.LearningPathIntegrationTest ► testUpdateLearningPathProgress()

Failed test found in: build/test-results/test/TEST-de.tum.cit.aet.artemis.atlas.learningpath.LearningPathIntegrationTest.xml Error: org.opentest4j.AssertionFailedError: [contains no completed competency]
Raw output
org.opentest4j.AssertionFailedError: [contains no completed competency] 
expected: 0
 but was: 17
	at app//de.tum.cit.aet.artemis.atlas.learningpath.LearningPathIntegrationTest.testUpdateLearningPathProgress(LearningPathIntegrationTest.java:418)
	at java.base@21.0.4/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base@21.0.4/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base@21.0.4/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
	at java.base@21.0.4/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
	at java.base@21.0.4/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
	at java.base@21.0.4/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
	at java.base@21.0.4/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)

verify(competencyProgressService).updateProgressByCompetencyAndUsersInCourseAsync(eq(createdCompetency));
}
Expand Down
Loading