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

General: Fix an issue with course deletion summary entries #9856

Merged
merged 12 commits into from
Jan 5, 2025
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record CourseDeletionSummaryDTO(long numberOfBuilds, long numberOfCommunicationPosts, long numberOfAnswerPosts) {
public record CourseDeletionSummaryDTO(long numberOfBuilds, long numberOfCommunicationPosts, long numberOfAnswerPosts, long numberProgrammingExercises, long numberTextExercises,
long numberFileUploadExercises, long numberModelingExercises, long numberQuizExercises, long numberExams, long numberLectures) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
import de.tum.cit.aet.artemis.exam.repository.ExerciseGroupRepository;
import de.tum.cit.aet.artemis.exam.service.ExamDeletionService;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
import de.tum.cit.aet.artemis.exercise.domain.ExerciseType;
import de.tum.cit.aet.artemis.exercise.domain.IncludedInOverallScore;
import de.tum.cit.aet.artemis.exercise.repository.ExerciseRepository;
import de.tum.cit.aet.artemis.exercise.repository.StudentParticipationRepository;
Expand Down Expand Up @@ -467,13 +468,26 @@ public Set<Course> findAllOnlineCoursesForPlatformForUser(String registrationId,
* @return the course deletion summary
*/
public CourseDeletionSummaryDTO getDeletionSummary(Course course) {
Long courseId = course.getId();

List<Long> programmingExerciseIds = course.getExercises().stream().map(Exercise::getId).toList();
long numberOfBuilds = buildJobRepository.countBuildJobsByExerciseIds(programmingExerciseIds);

List<Post> posts = postRepository.findAllByCourseId(course.getId());
List<Post> posts = postRepository.findAllByCourseId(courseId);
long numberOfCommunicationPosts = posts.size();
long numberOfAnswerPosts = answerPostRepository.countAnswerPostsByPostIdIn(posts.stream().map(Post::getId).toList());
ole-ve marked this conversation as resolved.
Show resolved Hide resolved
return new CourseDeletionSummaryDTO(numberOfBuilds, numberOfCommunicationPosts, numberOfAnswerPosts);
long numberLectures = lectureRepository.countByCourse_Id(courseId);
long numberExams = examRepository.countByCourse_Id(courseId);

Map<ExerciseType, Long> countByExerciseType = exerciseService.countByCourseIdGroupByType(courseId);
long numberProgrammingExercises = countByExerciseType.get(ExerciseType.PROGRAMMING);
long numberTextExercises = countByExerciseType.get(ExerciseType.TEXT);
long numberQuizExercises = countByExerciseType.get(ExerciseType.QUIZ);
long numberFileUploadExercises = countByExerciseType.get(ExerciseType.FILE_UPLOAD);
long numberModelingExercises = countByExerciseType.get(ExerciseType.MODELING);

ole-ve marked this conversation as resolved.
Show resolved Hide resolved
return new CourseDeletionSummaryDTO(numberOfBuilds, numberOfCommunicationPosts, numberOfAnswerPosts, numberProgrammingExercises, numberTextExercises,
numberFileUploadExercises, numberModelingExercises, numberQuizExercises, numberExams, numberLectures);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ SELECT COUNT(studentExam)
""")
long countGeneratedStudentExamsByExamWithoutTestRuns(@Param("examId") long examId);

long countByCourse_Id(Long courseId);

/**
* Returns the title of the exam with the given id.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package de.tum.cit.aet.artemis.exercise.dto;

import java.util.Objects;

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

public class ExerciseTypeCount {
ole-ve marked this conversation as resolved.
Show resolved Hide resolved

private final ExerciseType exerciseType;

private final long count;

public ExerciseTypeCount(Class<?> exerciseType, Long count) {
this.exerciseType = ExerciseType.getExerciseTypeFromClass(exerciseType.asSubclass(Exercise.class));
this.count = Objects.requireNonNullElse(count, 0L);
}
ole-ve marked this conversation as resolved.
Show resolved Hide resolved

public ExerciseType getExerciseType() {
return exerciseType;
}

public long getCount() {
return count;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import de.tum.cit.aet.artemis.core.repository.base.ArtemisJpaRepository;
import de.tum.cit.aet.artemis.exam.web.ExamResource;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
import de.tum.cit.aet.artemis.exercise.dto.ExerciseTypeCount;
import de.tum.cit.aet.artemis.exercise.dto.ExerciseTypeMetricsEntry;

/**
Expand Down Expand Up @@ -627,4 +628,21 @@ SELECT count(e) > 0
AND e.exerciseGroup IS NOT NULL
""")
boolean isExamExercise(@Param("exerciseId") long exerciseId);

/**
* Returns a mapping from exercise type to count for a given course id. Note that there are way fewer courses
* than exercise, so loading the course and joining the course is way faster than vice versa.
*
* @param courseId the courseId to get the exerciseType->count mapping for
* @return a list of mappings from exercise type to count
*/
@Query("""
SELECT new de.tum.cit.aet.artemis.exercise.dto.ExerciseTypeCount(TYPE(e), COUNT(e))
FROM Course c
JOIN c.exercises e
WHERE c.id = :courseId
AND TYPE(e) IN (ModelingExercise, TextExercise, ProgrammingExercise, QuizExercise, FileUploadExercise)
ole-ve marked this conversation as resolved.
Show resolved Hide resolved
GROUP BY TYPE(e)
""")
List<ExerciseTypeCount> countByCourseIdGroupedByType(long courseId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static java.time.ZonedDateTime.now;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
Expand Down Expand Up @@ -63,9 +64,11 @@
import de.tum.cit.aet.artemis.exam.service.ExamLiveEventsService;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
import de.tum.cit.aet.artemis.exercise.domain.ExerciseMode;
import de.tum.cit.aet.artemis.exercise.domain.ExerciseType;
import de.tum.cit.aet.artemis.exercise.domain.Submission;
import de.tum.cit.aet.artemis.exercise.domain.Team;
import de.tum.cit.aet.artemis.exercise.domain.participation.StudentParticipation;
import de.tum.cit.aet.artemis.exercise.dto.ExerciseTypeCount;
import de.tum.cit.aet.artemis.exercise.repository.ExerciseRepository;
import de.tum.cit.aet.artemis.exercise.repository.StudentParticipationRepository;
import de.tum.cit.aet.artemis.exercise.repository.SubmissionRepository;
Expand Down Expand Up @@ -829,4 +832,15 @@ public <T extends Exercise> T saveWithCompetencyLinks(T exercise, Function<T, T>
public void reconnectCompetencyExerciseLinks(Exercise exercise) {
exercise.getCompetencyLinks().forEach(link -> link.setExercise(exercise));
}

/**
* Returns a map from exercise type to count of exercise given a course id.
* If a course has no exercises for a specific type, the map contains an entry for that type with value 0.
*/
public Map<ExerciseType, Long> countByCourseIdGroupByType(Long courseId) {
Map<ExerciseType, Long> exerciseTypeCountMap = exerciseRepository.countByCourseIdGroupedByType(courseId).stream()
.collect(Collectors.toMap(ExerciseTypeCount::getExerciseType, ExerciseTypeCount::getCount));

return Arrays.stream(ExerciseType.values()).collect(Collectors.toMap(type -> type, type -> exerciseTypeCountMap.getOrDefault(type, 0L)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,6 @@ default Lecture findByIdWithLectureUnitsAndSlidesAndAttachmentsElseThrow(long le
GROUP BY l.course.id
""")
Set<CourseContentCount> countVisibleLectures(@Param("courseIds") Set<Long> courseIds, @Param("now") ZonedDateTime now);

long countByCourse_Id(Long courseId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,6 @@ export class CourseManagementTabBarComponent implements OnInit, OnDestroy, After
}

private getExistingSummaryEntries(): EntitySummary {
const numberRepositories =
this.course?.exercises
?.filter((exercise) => exercise.type === 'programming')
.map((exercise) => exercise?.numberOfParticipations ?? 0)
.reduce((repositorySum, numberOfParticipationsForRepository) => repositorySum + numberOfParticipationsForRepository, 0) ?? 0;

const numberOfExercisesPerType = new Map<ExerciseType, number>();
this.course?.exercises?.forEach((exercise) => {
if (exercise.type === undefined) {
Expand All @@ -219,23 +213,13 @@ export class CourseManagementTabBarComponent implements OnInit, OnDestroy, After
numberOfExercisesPerType.set(exercise.type, oldValue + 1);
});

const numberExams = this.course?.numberOfExams ?? 0;
const numberLectures = this.course?.lectures?.length ?? 0;
const numberStudents = this.course?.numberOfStudents ?? 0;
const numberTutors = this.course?.numberOfTeachingAssistants ?? 0;
const numberEditors = this.course?.numberOfEditors ?? 0;
const numberInstructors = this.course?.numberOfInstructors ?? 0;
const isTestCourse = this.course?.testCourse;

return {
'artemisApp.course.delete.summary.numberRepositories': numberRepositories,
'artemisApp.course.delete.summary.numberProgrammingExercises': numberOfExercisesPerType.get(ExerciseType.PROGRAMMING) ?? 0,
'artemisApp.course.delete.summary.numberModelingExercises': numberOfExercisesPerType.get(ExerciseType.MODELING) ?? 0,
'artemisApp.course.delete.summary.numberTextExercises': numberOfExercisesPerType.get(ExerciseType.TEXT) ?? 0,
'artemisApp.course.delete.summary.numberFileUploadExercises': numberOfExercisesPerType.get(ExerciseType.FILE_UPLOAD) ?? 0,
'artemisApp.course.delete.summary.numberQuizExercises': numberOfExercisesPerType.get(ExerciseType.QUIZ) ?? 0,
'artemisApp.course.delete.summary.numberExams': numberExams,
'artemisApp.course.delete.summary.numberLectures': numberLectures,
'artemisApp.course.delete.summary.numberStudents': numberStudents,
'artemisApp.course.delete.summary.numberTutors': numberTutors,
'artemisApp.course.delete.summary.numberEditors': numberEditors,
Expand All @@ -259,6 +243,13 @@ export class CourseManagementTabBarComponent implements OnInit, OnDestroy, After

return {
...this.getExistingSummaryEntries(),
'artemisApp.course.delete.summary.numberExams': summary.numberExams,
'artemisApp.course.delete.summary.numberLectures': summary.numberLectures,
'artemisApp.course.delete.summary.numberProgrammingExercises': summary.numberProgrammingExercises,
'artemisApp.course.delete.summary.numberTextExercises': summary.numberTextExercises,
'artemisApp.course.delete.summary.numberFileUploadExercises': summary.numberFileUploadExercises,
'artemisApp.course.delete.summary.numberQuizExercises': summary.numberQuizExercises,
'artemisApp.course.delete.summary.numberModelingExercises': summary.numberModelingExercises,
ole-ve marked this conversation as resolved.
Show resolved Hide resolved
'artemisApp.course.delete.summary.numberBuilds': summary.numberOfBuilds,
'artemisApp.course.delete.summary.numberCommunicationPosts': summary.numberOfCommunicationPosts,
'artemisApp.course.delete.summary.numberAnswerPosts': summary.numberOfAnswerPosts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,11 @@ export interface CourseDeletionSummaryDTO {
numberOfBuilds: number;
numberOfCommunicationPosts: number;
numberOfAnswerPosts: number;
numberProgrammingExercises: number;
numberTextExercises: number;
numberFileUploadExercises: number;
numberQuizExercises: number;
numberModelingExercises: number;
numberExams: number;
numberLectures: number;
}
Loading