Skip to content

Commit

Permalink
Development: Add alias for isTestRun for practice participations (#7172)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohannesStoehr authored Sep 15, 2023
1 parent 8cf6704 commit 8a8f11c
Show file tree
Hide file tree
Showing 33 changed files with 105 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/main/java/de/tum/in/www1/artemis/domain/Exercise.java
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ public Submission findLatestSubmissionWithRatedResultWithCompletionDate(Particip
boolean isAssessmentOver = ignoreAssessmentDueDate || ExerciseDateService.isAfterAssessmentDueDate(this);
boolean isProgrammingExercise = participation.getExercise() instanceof ProgrammingExercise;
// Check that submission was submitted in time (rated). For non programming exercises we check if the assessment due date has passed (if set)
boolean ratedOrPractice = Boolean.TRUE.equals(result.isRated()) || participation.isTestRun();
boolean ratedOrPractice = Boolean.TRUE.equals(result.isRated()) || participation.isPracticeMode();
boolean noProgrammingAndAssessmentOver = !isProgrammingExercise && isAssessmentOver;
// For programming exercises we check that the assessment due date has passed (if set) for manual results otherwise we always show the automatic result
boolean programmingAfterAssessmentOrAutomatic = isProgrammingExercise && ((result.isManual() && isAssessmentOver) || result.isAutomatic());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -673,8 +673,8 @@ public Set<Result> findResultsFilteredForStudents(Participation participation) {
public List<StudentParticipation> findRelevantParticipation(List<StudentParticipation> participations) {
List<StudentParticipation> participationOfExercise = participations.stream()
.filter(participation -> participation.getExercise() != null && participation.getExercise().equals(this)).toList();
List<StudentParticipation> gradedParticipations = participationOfExercise.stream().filter(participation -> !participation.isTestRun()).toList();
List<StudentParticipation> practiceParticipations = participationOfExercise.stream().filter(Participation::isTestRun).toList();
List<StudentParticipation> gradedParticipations = participationOfExercise.stream().filter(participation -> !participation.isPracticeMode()).toList();
List<StudentParticipation> practiceParticipations = participationOfExercise.stream().filter(Participation::isPracticeMode).toList();

if (gradedParticipations.size() > 1) {
gradedParticipations = super.findRelevantParticipation(gradedParticipations);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/tum/in/www1/artemis/domain/Result.java
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public void setRatedIfNotAfterDueDate() {
if (submission.getType() == SubmissionType.INSTRUCTOR || submission.getType() == SubmissionType.TEST) {
this.rated = true;
}
else if (submission.getType() == SubmissionType.ILLEGAL || participation.isTestRun()) {
else if (submission.getType() == SubmissionType.ILLEGAL || participation.isPracticeMode()) {
this.rated = false;
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,25 @@ public void setTestRun(boolean testRun) {
this.testRun = testRun;
}

/**
* Same as {@link #isTestRun} since {@link Participation#testRun} is used to determine if a participation in a course exercise is used for practice purposes
*
* @return true if the participation is only used for practicing after the due date
*/
@JsonIgnore
public boolean isPracticeMode() {
return Boolean.TRUE.equals(testRun);
}

/**
* Same as {@link #setTestRun} since {@link Participation#testRun} is used to determine if a participation in a course exercise is used for practice purposes
*
* @param practiceMode sets the testRun flag to this value
*/
public void setPracticeMode(boolean practiceMode) {
this.testRun = practiceMode;
}

public Set<Result> getResults() {
return results;
}
Expand Down Expand Up @@ -282,7 +301,7 @@ private <T extends Submission> Optional<T> findLatestSubmission(boolean includeI
* @return the same string with "practice-" added to the front if this is a test run participation
*/
public String addPracticePrefixIfTestRun(String string) {
return (isTestRun() ? "practice-" : "") + string;
return (isPracticeMode() ? "practice-" : "") + string;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public CourseForDashboardDTO getScoresAndParticipationResults(Course course, Gra
// TODO: Look into refactoring the fetchParticipationsWithSubmissionsAndResultsForCourses method in the CourseService to always initialize the participations (to an
// empty list if there aren't any). This way you don't need this very unintuitive check for the initialization state.
if (Hibernate.isInitialized(exercise.getStudentParticipations())) {
exercise.getStudentParticipations().stream().filter(participation -> !participation.isTestRun()).forEach(participation -> {
exercise.getStudentParticipations().stream().filter(participation -> !participation.isPracticeMode()).forEach(participation -> {
participation.setExercise(exercise);
gradedStudentParticipations.add(participation);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public StudentParticipation startExercise(Exercise exercise, Participant partici
public StudentParticipation startExerciseWithInitializationDate(Exercise exercise, Participant participant, boolean createInitialSubmission, ZonedDateTime initializationDate) {
// common for all exercises
Optional<StudentParticipation> optionalStudentParticipation = findOneByExerciseAndParticipantAnyState(exercise, participant);
if (optionalStudentParticipation.isPresent() && optionalStudentParticipation.get().isTestRun() && exercise.isCourseExercise()) {
if (optionalStudentParticipation.isPresent() && optionalStudentParticipation.get().isPracticeMode() && exercise.isCourseExercise()) {
// In case there is already a practice participation, set it to inactive
optionalStudentParticipation.get().setInitializationState(InitializationState.INACTIVE);
studentParticipationRepository.saveAndFlush(optionalStudentParticipation.get());
Expand Down Expand Up @@ -285,7 +285,7 @@ public StudentParticipation startPracticeMode(Exercise exercise, Participant par
participation.setInitializationState(InitializationState.UNINITIALIZED);
participation.setExercise(exercise);
participation.setParticipant(participant);
participation.setTestRun(true);
participation.setPracticeMode(true);
participation = studentParticipationRepository.saveAndFlush(participation);
}
else {
Expand Down Expand Up @@ -394,7 +394,7 @@ public ProgrammingExerciseStudentParticipation resumeProgrammingExercise(Program

// If a graded participation gets reset after the due date set the state back to finished. Otherwise, the participation is initialized
var dueDate = ExerciseDateService.getDueDate(participation);
if (!participation.isTestRun() && dueDate.isPresent() && ZonedDateTime.now().isAfter(dueDate.get())) {
if (!participation.isPracticeMode() && dueDate.isPresent() && ZonedDateTime.now().isAfter(dueDate.get())) {
participation.setInitializationState(InitializationState.FINISHED);
}
else {
Expand Down Expand Up @@ -646,7 +646,7 @@ public void cleanupBuildPlan(ProgrammingExerciseStudentParticipation participati

// If a graded participation gets cleaned up after the due date set the state back to finished. Otherwise, the participation is initialized
var dueDate = ExerciseDateService.getDueDate(participation);
if (!participation.isTestRun() && dueDate.isPresent() && ZonedDateTime.now().isAfter(dueDate.get())) {
if (!participation.isPracticeMode() && dueDate.isPresent() && ZonedDateTime.now().isAfter(dueDate.get())) {
participation.setInitializationState(InitializationState.FINISHED);
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ private Language getJPlagProgrammingLanguage(ProgrammingExercise programmingExer
public List<ProgrammingExerciseParticipation> filterStudentParticipationsForComparison(ProgrammingExercise programmingExercise, int minimumScore) {
var studentParticipations = studentParticipationRepository.findAllForPlagiarism(programmingExercise.getId());

return studentParticipations.parallelStream().filter(participation -> !participation.isTestRun())
return studentParticipations.parallelStream().filter(participation -> !participation.isPracticeMode())
.filter(participation -> participation instanceof ProgrammingExerciseParticipation).map(participation -> (ProgrammingExerciseParticipation) participation)
.filter(participation -> participation.getVcsRepositoryUrl() != null).filter(participation -> {
Submission submission = participation.findLatestSubmission().orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ private Path createZipForRepositoryWithParticipation(final ProgrammingExercise p
return null;
}

if (repositoryExportOptions.isExcludePracticeSubmissions() && participation.isTestRun()) {
if (repositoryExportOptions.isExcludePracticeSubmissions() && participation.isPracticeMode()) {
log.debug("Ignoring practice participation {}", participation);
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,11 @@ private Result processNewProgrammingExerciseResult(final ProgrammingExercisePart
// test run repository).
// Student test exam participations will still be locked by this.
SubmissionPolicy submissionPolicy = programmingExerciseRepository.findWithSubmissionPolicyById(programmingExercise.getId()).orElseThrow().getSubmissionPolicy();
if (submissionPolicy instanceof LockRepositoryPolicy policy && !((ProgrammingExerciseStudentParticipation) participation).isTestRun()) {
if (submissionPolicy instanceof LockRepositoryPolicy policy && !((ProgrammingExerciseStudentParticipation) participation).isPracticeMode()) {
submissionPolicyService.handleLockRepositoryPolicy(processedResult, (Participation) participation, policy);
}

if (programmingSubmission.getLatestResult() != null && programmingSubmission.getLatestResult().isManual() && !((Participation) participation).isTestRun()) {
if (programmingSubmission.getLatestResult() != null && programmingSubmission.getLatestResult().isManual() && !((Participation) participation).isPracticeMode()) {
// Note: in this case, we do not want to save the processedResult, but we only want to update the latest semi-automatic one
Result updatedLatestSemiAutomaticResult = updateLatestSemiAutomaticResultWithNewAutomaticFeedback(programmingSubmission.getLatestResult().getId(), processedResult);
// Adding back dropped submission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,8 @@ private boolean isAllowedToSubmit(ProgrammingExerciseStudentParticipation partic

private boolean isAllowedToSubmitForCourseExercise(ProgrammingExerciseStudentParticipation participation, ProgrammingSubmission programmingSubmission) {
var dueDate = ExerciseDateService.getDueDate(participation);
if (dueDate.isEmpty() || participation.isTestRun()) {
// Without a due date or in the practice mode, the student can always submit
if (dueDate.isEmpty() || participation.isPracticeMode()) {
return true;
}
return dueDate.get().plusSeconds(PROGRAMMING_GRACE_PERIOD_SECONDS).isAfter(programmingSubmission.getSubmissionDate());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ public ResponseEntity<ProgrammingExerciseStudentParticipation> resumeParticipati

// There is a second participation of that student in the exericse that is inactive/finished now
Optional<StudentParticipation> optionalOtherStudentParticipation = participationService.findOneByExerciseAndParticipantAnyStateAndTestRun(programmingExercise, user,
!participation.isTestRun());
!participation.isPracticeMode());
if (optionalOtherStudentParticipation.isPresent()) {
StudentParticipation otherParticipation = optionalOtherStudentParticipation.get();
if (participation.getInitializationState() == InitializationState.INACTIVE) {
Expand Down Expand Up @@ -371,7 +371,7 @@ public ResponseEntity<ProgrammingExerciseStudentParticipation> requestFeedback(@
private boolean isAllowedToParticipateInProgrammingExercise(ProgrammingExercise programmingExercise, @Nullable StudentParticipation participation) {
if (participation != null) {
// only regular participation before the due date; only practice run afterwards
return participation.isTestRun() == exerciseDateService.isAfterDueDate(participation);
return participation.isPracticeMode() == exerciseDateService.isAfterDueDate(participation);
}
else {
return programmingExercise.getDueDate() == null || now().isBefore(programmingExercise.getDueDate());
Expand Down Expand Up @@ -424,7 +424,7 @@ public ResponseEntity<Participation> updateParticipation(@PathVariable long exer
Optional<GradingScale> gradingScale = gradingScaleService.findGradingScaleByCourseId(participation.getExercise().getCourseViaExerciseGroupOrCourseMember().getId());

// Presentation Score is only valid for non practice participations
if (participation.isTestRun()) {
if (participation.isPracticeMode()) {
throw new BadRequestAlertException("Presentation score is not allowed for practice participations", ENTITY_NAME, "presentationScoreInvalid");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,22 @@ export class StudentParticipation extends Participation {
super(type ?? ParticipationType.STUDENT);
}
}

/**
* Checks if the participation is used for practicing in a course exercise. This is the case if testRun is set to true
* @param studentParticipation the participation to check
*/
export function isPracticeMode(studentParticipation: StudentParticipation | undefined): boolean | undefined {
return studentParticipation?.testRun;
}

/**
* Stores whether the participation is used for practicing in a course exercise.
* @param studentParticipation the participation that should store if it is used for practicing
* @param practiceMode true, if it is used for practicing
*/
export function setPracticeMode(studentParticipation: StudentParticipation | undefined, practiceMode: boolean) {
if (studentParticipation) {
studentParticipation.testRun = practiceMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ProgrammingSubmission } from 'app/entities/programming-submission.model
import { SubmissionType } from 'app/entities/submission.model';
import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model';
import { AssessmentType } from 'app/entities/assessment-type.model';
import { isPracticeMode } from 'app/entities/participation/student-participation.model';

const BAMBOO_RESULT_LEGACY_TIMESTAMP = 1557526348000;

Expand Down Expand Up @@ -42,7 +43,7 @@ export const createCommitUrl = (
const studentParticipation = participation as ProgrammingExerciseStudentParticipation;
if (studentParticipation.repositoryUrl) {
repoSlugPostfix = studentParticipation.participantIdentifier;
if (studentParticipation.testRun) {
if (isPracticeMode(studentParticipation)) {
repoSlugPostfix = 'practice-' + repoSlugPostfix;
}
}
Expand Down Expand Up @@ -75,7 +76,7 @@ export const isResultPreliminary = (latestResult: Result, programmingExercise?:
if (!programmingExercise) {
return false;
}
if (latestResult.participation?.type === ParticipationType.PROGRAMMING && (latestResult.participation as ProgrammingExerciseStudentParticipation).testRun) {
if (latestResult.participation?.type === ParticipationType.PROGRAMMING && isPracticeMode(latestResult.participation)) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ExerciseServicable } from 'app/exercises/shared/exercise/exercise.servi
import { map, mergeMap, mergeWith, takeUntil } from 'rxjs/operators';
import { ExerciseUpdateWarningComponent } from 'app/exercises/shared/exercise-update-warning/exercise-update-warning.component';
import { AlertService, AlertType } from 'app/core/util/alert.service';
import { StudentParticipation } from 'app/entities/participation/student-participation.model';
import { StudentParticipation, isPracticeMode } from 'app/entities/participation/student-participation.model';

export enum EditType {
IMPORT,
Expand Down Expand Up @@ -154,7 +154,7 @@ export const isStartExerciseAvailable = (exercise: Exercise, participation?: Stu
export const isResumeExerciseAvailable = (exercise: Exercise, participation?: StudentParticipation): boolean => {
const dueDate = participation?.individualDueDate ?? exercise.dueDate;
// A normal participation may only be resumed before the due date, a testrun only afterwards
return (!dueDate || dayjs().isBefore(dueDate)) === !participation?.testRun;
return (!dueDate || dayjs().isBefore(dueDate)) === !isPracticeMode(participation);
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { ParticipationService } from './participation.service';
import { ActivatedRoute } from '@angular/router';
import { StudentParticipation } from 'app/entities/participation/student-participation.model';
import { StudentParticipation, isPracticeMode } from 'app/entities/participation/student-participation.model';
import { ExerciseSubmissionState, ProgrammingSubmissionService, ProgrammingSubmissionState } from 'app/exercises/programming/participate/programming-submission.service';
import { ActionType } from 'app/shared/delete-dialog/delete-dialog.model';
import { HttpErrorResponse } from '@angular/common/http';
Expand Down Expand Up @@ -191,7 +191,7 @@ export class ParticipationComponent implements OnInit, OnDestroy {
case FilterProp.NO_SUBMISSIONS:
return participation.submissionCount === 0;
case FilterProp.NO_PRACTICE:
return !participation.testRun;
return !isPracticeMode(participation);
case FilterProp.ALL:
default:
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import { hasExerciseDueDatePassed } from 'app/exercises/shared/exercise/exercise
import { faCircleNotch, faExclamationCircle, faExclamationTriangle, faFile } from '@fortawesome/free-solid-svg-icons';
import { faCircle } from '@fortawesome/free-regular-svg-icons';
import { Badge, ResultService } from 'app/exercises/shared/result/result.service';
import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model';
import { ExerciseCacheService } from 'app/exercises/shared/exercise/exercise-cache.service';
import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service';
import { isPracticeMode } from 'app/entities/participation/student-participation.model';

@Component({
selector: 'jhi-result',
Expand Down Expand Up @@ -191,7 +191,7 @@ export class ResultComponent implements OnInit, OnChanges {
if (
this.participation &&
isProgrammingExerciseStudentParticipation(this.participation) &&
!(this.participation as ProgrammingExerciseStudentParticipation).testRun &&
!isPracticeMode(this.participation) &&
isResultPreliminary(this.result!, programmingExercise)
) {
if (programmingExercise?.assessmentType !== AssessmentType.AUTOMATIC) {
Expand Down
Loading

0 comments on commit 8a8f11c

Please sign in to comment.