Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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 @@ -305,7 +305,7 @@ SELECT COUNT(c)
/**
* Get the number of Complaints for all tutors of an exam
*
* @param examId - id of the exercise
* @param exerciseIds - ids of the exercises to consider
* @return list of TutorLeaderboardComplaints
*/
@Query("""
Expand All @@ -320,14 +320,13 @@ SELECT COUNT(c)
JOIN r.submission s
JOIN s.participation p
JOIN p.exercise e
JOIN e.exerciseGroup eg
WHERE c.complaintType = de.tum.cit.aet.artemis.assessment.domain.ComplaintType.COMPLAINT
AND eg.exam.id = :examId
AND e.id IN :exerciseIds
AND r.completionDate IS NOT NULL
AND r.assessor.id IS NOT NULL
GROUP BY r.assessor.id
""")
List<TutorLeaderboardComplaintsDTO> findTutorLeaderboardComplaintsByExamId(@Param("examId") long examId);
List<TutorLeaderboardComplaintsDTO> findTutorLeaderboardComplaintsByExerciseIds(@Param("exerciseIds") Collection<Long> exerciseIds);

/**
* Get the number of complaintResponses for all tutors assessments of a course
Expand Down Expand Up @@ -384,7 +383,7 @@ SELECT COUNT(c)
/**
* Get the number of complaintResponses for all tutors assessments of an exam
*
* @param examId - id of the exam
* @param exerciseIds - ids of the exercises to consider
* @return list of TutorLeaderboardComplaintResponses
*/
@Query("""
Expand All @@ -399,14 +398,13 @@ SELECT COUNT(c)
JOIN r.submission s
JOIN s.participation p
JOIN p.exercise e
JOIN e.exerciseGroup eg
WHERE c.complaintType = de.tum.cit.aet.artemis.assessment.domain.ComplaintType.COMPLAINT
AND eg.exam.id = :examId
AND e.id IN :exerciseIds
AND r.completionDate IS NOT NULL
AND c.accepted IS NOT NULL
GROUP BY cr.reviewer.id
""")
List<TutorLeaderboardComplaintResponsesDTO> findTutorLeaderboardComplaintResponsesByExamId(@Param("examId") long examId);
List<TutorLeaderboardComplaintResponsesDTO> findTutorLeaderboardComplaintResponsesByExerciseIds(@Param("exerciseIds") Collection<Long> exerciseIds);

// Valid JPQL syntax. Only SCA fails to properly detect the types.
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public interface ComplaintResponseRepository extends ArtemisJpaRepository<Compla
@Query("""
SELECT COUNT(DISTINCT cr)
FROM ComplaintResponse cr
JOIN cr.complaint c
JOIN c.result r
JOIN cr.complaint c
JOIN c.result r
WHERE r.exerciseId IN :exerciseIds
AND cr.submittedTime IS NOT NULL
AND c.complaintType = :complaintType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -49,9 +50,9 @@ public interface ResultRepository extends ArtemisJpaRepository<Result, Long> {

@Query("""
SELECT r
FROM Result r
LEFT JOIN FETCH r.assessor
WHERE r.id = :resultId
FROM Result r
LEFT JOIN FETCH r.assessor
WHERE r.id = :resultId
""")
Optional<Result> findByIdWithEagerAssessor(@Param("resultId") long resultId);

Expand Down Expand Up @@ -341,25 +342,25 @@ SELECT COUNT(r.id)
List<Long> countNumberOfLockedAssessmentsByOtherTutorsForExamExerciseForCorrectionRoundsIgnoreTestRuns(@Param("exerciseId") long exerciseId, @Param("tutorId") long tutorId);

/**
* count the number of finished assessments of an exam with given examId
* count the number of finished assessments of an exam with given exerciseIds
*
* @param examId id of the exam
* @return a list that contains the count of manual assessments for each studentParticipation of the exam
* @param exerciseIds ids of the exercises
* @return a list that contains the count of manual assessments for each studentParticipation of the exercise ids
*/
@Query("""
SELECT COUNT(r.id)
FROM StudentParticipation p
JOIN p.submissions s
JOIN s.results r
WHERE p.exercise.exerciseGroup.exam.id = :examId
WHERE p.exercise.id IN :exerciseIds
AND p.testRun = FALSE
AND s.submitted = TRUE
AND r.completionDate IS NOT NULL
AND r.rated = TRUE
AND r.assessor IS NOT NULL
GROUP BY p.id
""")
List<Long> countNumberOfFinishedAssessmentsByExamIdIgnoreTestRuns(@Param("examId") long examId);
List<Long> countNumberOfFinishedAssessmentsByExerciseIdsIgnoreTestRuns(@Param("exerciseIds") Collection<Long> exerciseIds);

@Query("""
SELECT COUNT(DISTINCT p)
Expand Down Expand Up @@ -518,15 +519,15 @@ default DueDateStat[] countNumberOfLockedAssessmentsByOtherTutorsForExamExercise
* Use this method only for exams!
* Given an exerciseId and the number of correctionRounds, return the number of assessments that have been finished, for that exerciseId and each correctionRound
*
* @param examId - the id of the exam we are interested in
* @param exerciseIds - the exercise ids of the exam we are interested in
* @param numberOfCorrectionRounds - the correction round we want finished assessments for
* @return an array of the number of assessments for the exercise for a given correction round
*/
default DueDateStat[] countNumberOfFinishedAssessmentsForExamForCorrectionRounds(long examId, int numberOfCorrectionRounds) {
default DueDateStat[] countNumberOfFinishedAssessmentsForExamForCorrectionRounds(Collection<Long> exerciseIds, int numberOfCorrectionRounds) {

// here we receive a list which contains an entry for each student participation of the exam.
// the entry simply is the number of already created and submitted manual results, so the number is either 1 or 2
List<Long> countList = countNumberOfFinishedAssessmentsByExamIdIgnoreTestRuns(examId);
List<Long> countList = countNumberOfFinishedAssessmentsByExerciseIdsIgnoreTestRuns(exerciseIds);
return convertDatabaseResponseToDueDateStats(countList, numberOfCorrectionRounds);
}

Expand Down Expand Up @@ -646,15 +647,13 @@ default long countNumberOfAssessments(Set<Long> exerciseIds) {
JOIN r.submission s
JOIN s.participation p
JOIN p.exercise e
JOIN e.exerciseGroup eg
JOIN eg.exam ex
JOIN r.assessor a
LEFT JOIN FETCH Rating rating ON rating.result = r
WHERE r.completionDate IS NOT NULL
AND ex.id = :examId
AND e.id IN :exerciseIds
GROUP BY r.assessor.id
""")
List<TutorLeaderboardAssessmentsDTO> findTutorLeaderboardAssessmentByExamId(@Param("examId") long examId);
List<TutorLeaderboardAssessmentsDTO> findTutorLeaderboardAssessmentByExerciseIds(@Param("exerciseIds") Collection<Long> exerciseIds);

/**
* This function is used for submitting a manual assessment/result.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
Expand All @@ -23,7 +24,6 @@
import de.tum.cit.aet.artemis.core.domain.User;
import de.tum.cit.aet.artemis.core.dto.TutorLeaderboardDTO;
import de.tum.cit.aet.artemis.core.repository.UserRepository;
import de.tum.cit.aet.artemis.exam.domain.Exam;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;

@Profile(PROFILE_CORE)
Expand Down Expand Up @@ -74,15 +74,15 @@ public List<TutorLeaderboardDTO> getCourseLeaderboard(Course course, Set<Long> e
/**
* Returns tutor leaderboards for the specified course.
*
* @param course - course for which leaderboard is fetched
* @param exam - the exam for which the leaderboard will be fetched
* @param course - course for which leaderboard is fetched
* @param exerciseIds - the exercise ids for which the leaderboard will be fetched
* @return list of tutor leaderboard objects
*/
public List<TutorLeaderboardDTO> getExamLeaderboard(Course course, Exam exam) {
public List<TutorLeaderboardDTO> getExamLeaderboard(Course course, Collection<Long> exerciseIds) {
var tutors = userRepository.getTutors(course);
var tutorLeaderboardAssessments = resultRepository.findTutorLeaderboardAssessmentByExamId(exam.getId());
var tutorLeaderboardComplaints = complaintRepository.findTutorLeaderboardComplaintsByExamId(exam.getId());
var tutorLeaderboardComplaintResponses = complaintRepository.findTutorLeaderboardComplaintResponsesByExamId(exam.getId());
var tutorLeaderboardAssessments = resultRepository.findTutorLeaderboardAssessmentByExerciseIds(exerciseIds);
var tutorLeaderboardComplaints = complaintRepository.findTutorLeaderboardComplaintsByExerciseIds(exerciseIds);
var tutorLeaderboardComplaintResponses = complaintRepository.findTutorLeaderboardComplaintResponsesByExerciseIds(exerciseIds);
return aggregateTutorLeaderboardData(tutors, tutorLeaderboardAssessments, tutorLeaderboardComplaints, new ArrayList<>(), tutorLeaderboardComplaintResponses,
new ArrayList<>(), true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

import de.tum.cit.aet.artemis.atlas.config.AtlasEnabled;
import de.tum.cit.aet.artemis.atlas.domain.competency.Competency;
import de.tum.cit.aet.artemis.atlas.domain.competency.CourseCompetency;
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRepository;
import de.tum.cit.aet.artemis.atlas.repository.CourseCompetencyRepository;

@Controller
@Conditional(AtlasEnabled.class)
Expand All @@ -17,15 +19,18 @@ public class CompetencyRepositoryApi extends AbstractAtlasApi {

private final CompetencyRepository competencyRepository;

public CompetencyRepositoryApi(CompetencyRepository competencyRepository) {
private final CourseCompetencyRepository courseCompetencyRepository;

public CompetencyRepositoryApi(CompetencyRepository competencyRepository, CourseCompetencyRepository courseCompetencyRepository) {
this.competencyRepository = competencyRepository;
this.courseCompetencyRepository = courseCompetencyRepository;
}

public Set<Competency> findAllByCourseId(long courseId) {
public Set<Competency> findAllCompetenciesByCourseId(long courseId) {
return competencyRepository.findAllByCourseId(courseId);
}

public Competency findByIdElseThrow(long competencyId) {
return competencyRepository.findByIdElseThrow(competencyId);
public CourseCompetency findCompetencyOrPrerequisiteByIdElseThrow(long competencyId) {
return courseCompetencyRepository.findByIdElseThrow(competencyId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ public abstract class CourseCompetency extends BaseCompetency {
@JsonIgnore
public static final int DEFAULT_MASTERY_THRESHOLD = 100;

@JsonIgnore
public static final int MAX_TITLE_LENGTH = 255;

@Column(name = "soft_due_date")
private ZonedDateTime softDueDate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ public void cleanUpContainers() {
// Cleanup all dangling build containers after the application has started
try {
danglingBuildContainers = dockerClient.listContainersCmd().withShowAll(true).exec().stream()
.filter(container -> container.getNames()[0].startsWith("/" + buildContainerPrefix)).toList();
.filter(container -> container.getNames() != null && container.getNames().length > 0 && container.getNames()[0].startsWith("/" + buildContainerPrefix))
.toList();
}
catch (Exception ex) {
if (DockerUtil.isDockerNotAvailable(ex)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public interface ChannelRepository extends ArtemisJpaRepository<Channel, Long> {
""")
Set<Channel> findLectureChannelsByCourseId(@Param("courseId") Long courseId);

@Query("""
SELECT channel.name
FROM Channel channel
WHERE channel.lecture.id = :lectureId
""")
String findChannelNameByLectureId(@Param("lectureId") Long lectureId);

@Query("""
SELECT channel
FROM Channel channel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,15 @@ public void createChannelsForLectures(List<Lecture> lectures, Course course, Use
* Creates a channel for a lecture and sets the channel name of the lecture accordingly.
*
* @param lecture the lecture to create the channel for
* @param channelName the name of the channel
* @param channelName the name of the channel (optional), will be generated from the lecture title if not provided
*
* @return the created channel name
*/
public void createLectureChannel(Lecture lecture, Optional<String> channelName) {
public String createLectureChannel(Lecture lecture, Optional<String> channelName) {
Channel channelToCreate = createDefaultChannel(channelName, "lecture-", lecture.getTitle());
channelToCreate.setLecture(lecture);
Channel createdChannel = createChannel(lecture.getCourse(), channelToCreate, Optional.of(userRepository.getUserWithGroupsAndAuthorities()));
lecture.setChannelName(createdChannel.getName());
Channel createdChannel = createChannel(lecture.getCourse(), channelToCreate, Optional.of(userRepository.getUser()));
return createdChannel.getName();
}

/**
Expand All @@ -308,7 +310,7 @@ public Channel createExerciseChannel(Exercise exercise, Optional<String> channel
}
Channel channelToCreate = createDefaultChannel(channelName, "exercise-", exercise.getTitle());
channelToCreate.setExercise(exercise);
return createChannel(exercise.getCourseViaExerciseGroupOrCourseMember(), channelToCreate, Optional.of(userRepository.getUserWithGroupsAndAuthorities()));
return createChannel(exercise.getCourseViaExerciseGroupOrCourseMember(), channelToCreate, Optional.of(userRepository.getUser()));
}

/**
Expand All @@ -320,7 +322,7 @@ public Channel createExerciseChannel(Exercise exercise, Optional<String> channel
public void createExamChannel(Exam exam, Optional<String> channelName) {
Channel channelToCreate = createDefaultChannel(channelName, "exam-", exam.getTitle());
channelToCreate.setExam(exam);
Channel createdChannel = createChannel(exam.getCourse(), channelToCreate, Optional.of(userRepository.getUserWithGroupsAndAuthorities()));
Channel createdChannel = createChannel(exam.getCourse(), channelToCreate, Optional.of(userRepository.getUser()));
exam.setChannelName(createdChannel.getName());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public Course loadCourseWithExercisesLecturesLectureUnitsCompetenciesAndPrerequi
}
Set<Competency> competencies = new HashSet<>();
if (competencyRepositoryApi.isPresent()) {
competencies = competencyRepositoryApi.orElseThrow().findAllByCourseId(courseId);
competencies = competencyRepositoryApi.orElseThrow().findAllCompetenciesByCourseId(courseId);
}
Set<Prerequisite> prerequisites = new HashSet<>();
if (prerequisitesApi.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,4 +526,20 @@ private static Map<Long, Integer> convertListOfCountsIntoMap(List<long[]> examId
WHERE exam.course.id = :courseId
""")
Set<Long> findExamIdsByCourseId(@Param("courseId") long courseId);

@Query("""
SELECT DISTINCT ex.id
FROM Exam exam
JOIN exam.exerciseGroups eg
JOIN eg.exercises ex
WHERE exam.id = :examId
""")
Set<Long> findExerciseIdsByExamId(@Param("examId") Long examId);

@Query("""
SELECT ex.numberOfCorrectionRoundsInExam
FROM Exam ex
WHERE ex.id = :examId
""")
int findNumberOfCorrectionRoundsByExamId(@Param("examId") Long examId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1370,17 +1370,17 @@ public void setExamProperties(Exam exam) {
* @return data about an exam including all exercises, plus some data for the tutor as tutor status for assessment
*/
public StatsForDashboardDTO getStatsForExamAssessmentDashboard(Course course, Long examId) {
Exam exam = examRepository.findWithExerciseGroupsAndExercisesByIdOrElseThrow(examId);
Set<Long> exerciseIds = exam.getExerciseGroups().stream().flatMap(exerciseGroup -> exerciseGroup.getExercises().stream()).map(DomainObject::getId)
.collect(Collectors.toSet());
StatsForDashboardDTO stats = new StatsForDashboardDTO();
Set<Long> exerciseIds = examRepository.findExerciseIdsByExamId(examId);

final long numberOfSubmissions = submissionRepository.countByExamIdSubmittedSubmissionsIgnoreTestRuns(examId)
+ programmingExerciseRepository.countSubmissionsByExamIdSubmitted(examId);
final long numberOfSubmissions = submissionRepository.countByExerciseIdsSubmittedSubmissionsIgnoreTestRuns(exerciseIds)
+ programmingExerciseRepository.countSubmissionsByExerciseIdsSubmitted(exerciseIds);
stats.setNumberOfSubmissions(new DueDateStat(numberOfSubmissions, 0));

DueDateStat[] numberOfAssessmentsOfCorrectionRounds = resultRepository.countNumberOfFinishedAssessmentsForExamForCorrectionRounds(examId,
exam.getNumberOfCorrectionRoundsInExam());
int numberOfCorrectionRoundsInExam = examRepository.findNumberOfCorrectionRoundsByExamId(examId);

DueDateStat[] numberOfAssessmentsOfCorrectionRounds = resultRepository.countNumberOfFinishedAssessmentsForExamForCorrectionRounds(exerciseIds,
numberOfCorrectionRoundsInExam);
stats.setNumberOfAssessmentsOfCorrectionRounds(numberOfAssessmentsOfCorrectionRounds);

final long numberOfComplaints = complaintRepository.countByExerciseIdsAndComplaintType(exerciseIds, ComplaintType.COMPLAINT);
Expand All @@ -1389,13 +1389,14 @@ public StatsForDashboardDTO getStatsForExamAssessmentDashboard(Course course, Lo
final long numberOfComplaintResponses = complaintResponseRepository.countComplaintResponsesForExerciseIdsAndComplaintType(exerciseIds, ComplaintType.COMPLAINT);
stats.setNumberOfOpenComplaints(numberOfComplaints - numberOfComplaintResponses);

final long numberOfAssessmentLocks = submissionRepository.countLockedSubmissionsByUserIdAndExamId(userRepository.getUserWithGroupsAndAuthorities().getId(), examId);
final long numberOfAssessmentLocks = submissionRepository.countLockedSubmissionsByUserIdAndExerciseIds(userRepository.getUserWithGroupsAndAuthorities().getId(),
exerciseIds);
stats.setNumberOfAssessmentLocks(numberOfAssessmentLocks);

final long totalNumberOfAssessmentLocks = submissionRepository.countLockedSubmissionsByExamId(examId);
final long totalNumberOfAssessmentLocks = submissionRepository.countLockedSubmissionsByExerciseIds(exerciseIds);
stats.setTotalNumberOfAssessmentLocks(totalNumberOfAssessmentLocks);

List<TutorLeaderboardDTO> leaderboardEntries = tutorLeaderboardService.getExamLeaderboard(course, exam);
List<TutorLeaderboardDTO> leaderboardEntries = tutorLeaderboardService.getExamLeaderboard(course, exerciseIds);
stats.setTutorLeaderboardEntries(leaderboardEntries);
return stats;
}
Expand Down
Loading
Loading