Skip to content
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 @@ -230,12 +230,16 @@ public CourseForDashboardDTO getScoresAndParticipationResults(Course course, Gra
Map<ExerciseType, CourseScoresDTO> scoresPerExerciseType = calculateCourseScoresPerExerciseType(course, gradedStudentParticipations, userId, plagiarismCases);

// Get participation results (used in course-statistics.component).
List<Result> participationResults = new ArrayList<>();
List<ParticipationResultDTO> participationResults = new ArrayList<>();
for (StudentParticipation studentParticipation : gradedStudentParticipations) {
if (studentParticipation.getResults() != null && !studentParticipation.getResults().isEmpty()) {
Result participationResult = getResultForParticipation(studentParticipation, studentParticipation.getIndividualDueDate());
participationResult.setParticipation(studentParticipation);
Result result = getResultForParticipation(studentParticipation, studentParticipation.getIndividualDueDate());
var participationResult = new ParticipationResultDTO(result.getScore(), result.isRated(), studentParticipation.getId());
participationResults.add(participationResult);
// this line is an important workaround. It prevents that the whole tree
// "result -> participation -> exercise -> course -> exercises -> studentParticipations -> submissions -> results" is sent again to the client which is useless
// TODO: in the future, we need a better solution to prevent this
studentParticipation.setExercise(null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.fasterxml.jackson.annotation.JsonInclude;

import de.tum.in.www1.artemis.domain.Course;
import de.tum.in.www1.artemis.domain.Result;

/**
* Returned by the for-dashboard resources.
Expand All @@ -23,5 +22,5 @@
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record CourseForDashboardDTO(Course course, CourseScoresDTO totalScores, CourseScoresDTO textScores, CourseScoresDTO programmingScores, CourseScoresDTO modelingScores,
CourseScoresDTO fileUploadScores, CourseScoresDTO quizScores, List<Result> participationResults) {
CourseScoresDTO fileUploadScores, CourseScoresDTO quizScores, List<ParticipationResultDTO> participationResults) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package de.tum.in.www1.artemis.web.rest.dto;

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record ParticipationResultDTO(Double score, Boolean rated, Long participationId) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { ParticipationResultDTO } from 'app/course/manage/course-for-dashboard-dto';
import { ScoresPerExerciseType } from 'app/entities/exercise.model';
import { Result } from 'app/entities/result.model';
import { CourseScores } from 'app/course/course-scores/course-scores';

/**
Expand All @@ -24,7 +24,7 @@ export class ScoresStorageService {
/**
* This map stores the {@link Result} object for each {@link Participation} of the currently logged-in user. The number is the id of the participation.
*/
private storedParticipationResults: Map<number, Result> = new Map();
private storedParticipationResults: Map<number, ParticipationResultDTO> = new Map();

getStoredTotalScores(courseId: number): CourseScores | undefined {
return this.storedTotalScores.get(courseId);
Expand All @@ -42,13 +42,13 @@ export class ScoresStorageService {
this.storedScoresPerExerciseType.set(courseId, scoresPerExerciseType);
}

getStoredParticipationResult(participationId: number): Result | undefined {
getStoredParticipationResult(participationId: number): ParticipationResultDTO | undefined {
return this.storedParticipationResults.get(participationId);
}

setStoredParticipationResults(participationResults?: Result[]): void {
for (const result of participationResults ?? []) {
this.storedParticipationResults.set(result.participation!.id!, result);
setStoredParticipationResults(participationResults?: ParticipationResultDTO[]): void {
for (const participationResult of participationResults ?? []) {
this.storedParticipationResults.set(participationResult.participationId, participationResult);
}
}
}
10 changes: 8 additions & 2 deletions src/main/webapp/app/course/manage/course-for-dashboard-dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Course } from 'app/entities/course.model';
import { CourseScores } from 'app/course/course-scores/course-scores';
import { Result } from 'app/entities/result.model';

export class CourseForDashboardDTO {
course: Course;
Expand All @@ -13,7 +12,14 @@ export class CourseForDashboardDTO {
fileUploadScores: CourseScores;
quizScores: CourseScores;

participationResults: Result[];
participationResults: ParticipationResultDTO[];

constructor() {}
}

export class ParticipationResultDTO {
score?: number;
rated?: boolean;
participationId: number;
constructor() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { TranslateService } from '@ngx-translate/core';
import { Color, ScaleType } from '@swimlane/ngx-charts';
import { CourseScores } from 'app/course/course-scores/course-scores';
import { ScoresStorageService } from 'app/course/course-scores/scores-storage.service';
import { ParticipationResultDTO } from 'app/course/manage/course-for-dashboard-dto';
import { CourseStorageService } from 'app/course/manage/course-storage.service';
import { Course } from 'app/entities/course.model';
import { Exercise, ExerciseType, IncludedInOverallScore, ScoresPerExerciseType } from 'app/entities/exercise.model';
import { GradeDTO } from 'app/entities/grade-step.model';
import { GradeType } from 'app/entities/grading-scale.model';
import { InitializationState } from 'app/entities/participation/participation.model';
import { StudentParticipation } from 'app/entities/participation/student-participation.model';
import { Result } from 'app/entities/result.model';
import { GraphColors } from 'app/entities/statistics.model';
import { GradingSystemService } from 'app/grading-system/grading-system.service';
import { BarControlConfiguration, BarControlConfigurationProvider } from 'app/shared/tab-bar/tab-bar';
Expand Down Expand Up @@ -326,7 +326,7 @@ export class CourseStatisticsComponent implements OnInit, OnDestroy, AfterViewIn
} else {
exercise.studentParticipations.forEach((participation: StudentParticipation) => {
if (participation.id && participation.results?.length) {
const participationResult: Result | undefined = this.scoresStorageService.getStoredParticipationResult(participation.id);
const participationResult: ParticipationResultDTO | undefined = this.scoresStorageService.getStoredParticipationResult(participation.id);
if (participationResult?.rated) {
const roundedParticipationScore = roundValueSpecifiedByCourseSettings(participationResult.score!, this.course);
const cappedParticipationScore = Math.min(roundedParticipationScore, 100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ import { MockRouter } from '../../helpers/mocks/mock-router';
import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service';
import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service';
import { OnlineCourseConfiguration } from 'app/entities/online-course-configuration.model';
import { CourseForDashboardDTO } from 'app/course/manage/course-for-dashboard-dto';
import { CourseForDashboardDTO, ParticipationResultDTO } from 'app/course/manage/course-for-dashboard-dto';
import { CourseScores } from 'app/course/course-scores/course-scores';
import { ScoresStorageService } from 'app/course/course-scores/scores-storage.service';
import { CourseStorageService } from 'app/course/manage/course-storage.service';
import { Result } from 'app/entities/result.model';

describe('Course Management Service', () => {
let courseManagementService: CourseManagementService;
Expand All @@ -48,7 +47,7 @@ describe('Course Management Service', () => {
let courseForDashboard: CourseForDashboardDTO;
let courseScores: CourseScores;
let scoresPerExerciseType: ScoresPerExerciseType;
let participationResult: Result;
let participationResult: ParticipationResultDTO;
let onlineCourseConfiguration: OnlineCourseConfiguration;
let exercises: Exercise[];
let returnedFromService: any;
Expand Down Expand Up @@ -96,10 +95,8 @@ describe('Course Management Service', () => {
courseForDashboard.quizScores = courseScores;
courseForDashboard.textScores = courseScores;
courseForDashboard.fileUploadScores = courseScores;
participationResult = new Result();
const participation = new StudentParticipation();
participation.id = 432;
participationResult.participation = participation;
participationResult = new ParticipationResultDTO();
participationResult.participationId = 432;
courseForDashboard.participationResults = [participationResult];

scoresPerExerciseType = new Map<ExerciseType, CourseScores>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BarChartModule, PieChartModule } from '@swimlane/ngx-charts';
import { CourseScores } from 'app/course/course-scores/course-scores';
import { ScoresStorageService } from 'app/course/course-scores/scores-storage.service';
import { DueDateStat } from 'app/course/dashboards/due-date-stat.model';
import { ParticipationResultDTO } from 'app/course/manage/course-for-dashboard-dto';
import { CourseStorageService } from 'app/course/manage/course-storage.service';
import { Course } from 'app/entities/course.model';
import { ExerciseCategory } from 'app/entities/exercise-category.model';
Expand All @@ -15,7 +16,6 @@ import { FileUploadExercise } from 'app/entities/file-upload-exercise.model';
import { ModelingExercise } from 'app/entities/modeling-exercise.model';
import { ProgrammingExercise } from 'app/entities/programming-exercise.model';
import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model';
import { Result } from 'app/entities/result.model';
import { TreeviewModule } from 'app/exercises/programming/shared/code-editor/treeview/treeview.module';
import { CourseCompetenciesComponent } from 'app/overview/course-competencies/course-competencies.component';
import { CourseStatisticsComponent, NgxExercise } from 'app/overview/course-statistics/course-statistics.component';
Expand Down Expand Up @@ -360,7 +360,7 @@ describe('CourseStatisticsComponent', () => {
const courseToAdd = { ...course };
courseToAdd.exercises = [programmingExercise, quizExercise, ...modelingExercises, fileUploadExercise];
jest.spyOn(courseStorageService, 'getCourse').mockReturnValue(courseToAdd);
const mockParticipationResult: Result = { rated: true, score: 100 };
const mockParticipationResult: ParticipationResultDTO = { rated: true, score: 100, participationId: 1 };
jest.spyOn(scoresStorageService, 'getStoredParticipationResult').mockReturnValue(mockParticipationResult);
fixture.detectChanges();
comp.ngOnInit();
Expand All @@ -384,7 +384,7 @@ describe('CourseStatisticsComponent', () => {
const courseToAdd = { ...course };
courseToAdd.exercises = [...modelingExercises];
jest.spyOn(courseStorageService, 'getCourse').mockReturnValue(courseToAdd);
const mockParticipationResult: Result = { rated: true, score: 100 };
const mockParticipationResult: ParticipationResultDTO = { rated: true, score: 100, participationId: 1 };
jest.spyOn(scoresStorageService, 'getStoredParticipationResult').mockReturnValue(mockParticipationResult);
fixture.detectChanges();
comp.ngOnInit();
Expand Down Expand Up @@ -480,7 +480,7 @@ describe('CourseStatisticsComponent', () => {
});

it('should filter optional exercises correctly', () => {
const mockParticipationResult: Result = { rated: true, score: 100 };
const mockParticipationResult: ParticipationResultDTO = { rated: true, score: 100, participationId: 1 };
jest.spyOn(scoresStorageService, 'getStoredParticipationResult').mockReturnValue(mockParticipationResult);
comp.toggleNotIncludedInScoreExercises();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ describe('ScoresStorageService', () => {
participation2.id = 2;

scoresStorageService.setStoredParticipationResults([
{ successful: true, participation: participation1 },
{ successful: false, participation: participation2 },
{ score: 100, participationId: participation1.id },
{ score: 0, participationId: participation2.id },
]);
expect(scoresStorageService.getStoredParticipationResult(1)).toEqual({ successful: true, participation: participation1 });
expect(scoresStorageService.getStoredParticipationResult(1)).toEqual({ score: 100, participationId: participation1.id });
// Should return undefined for an unknown participation id.
expect(scoresStorageService.getStoredParticipationResult(3)).toBeUndefined();
});
Expand All @@ -24,7 +24,7 @@ describe('ScoresStorageService', () => {
const scoresStorageService = new ScoresStorageService();
const participation = new StudentParticipation();
participation.id = 234;
scoresStorageService.setStoredParticipationResults([{ successful: true, participation }]);
scoresStorageService.setStoredParticipationResults([{ score: 100, participationId: participation.id }]);
expect(scoresStorageService.getStoredParticipationResult(1)).toBeUndefined();
});
});