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

Programming exercises: Add group feedback feature to feedback analysis table #9884

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
2aef101
added tests and documentation
az108 Nov 10, 2024
862e9b0
fix
az108 Nov 10, 2024
0fdcfe9
Merge remote-tracking branch 'origin/develop' into feature/programmin…
az108 Nov 11, 2024
8fb7be1
johannes feedback
az108 Nov 11, 2024
ae13615
johannes feedback
az108 Nov 11, 2024
15d3fba
johannes feedback
az108 Nov 11, 2024
7f32c6f
tests fix
az108 Nov 11, 2024
3703ca0
johannes feedback
az108 Nov 11, 2024
3b32032
bilel feedback
az108 Nov 12, 2024
f0b99a3
florian feedback
az108 Nov 12, 2024
4d5a609
client test feedback
az108 Nov 12, 2024
cfd9442
client test feedback
az108 Nov 12, 2024
30ebcb7
client test feedback
az108 Nov 12, 2024
dcfd0a8
Merge branch 'develop' into feature/programming-exercises/add-affecte…
az108 Nov 12, 2024
72b482e
client test
az108 Nov 12, 2024
06c2462
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Nov 12, 2024
be28769
ramona feedback
az108 Nov 14, 2024
fe3cb3b
ramona feedback
az108 Nov 14, 2024
3dee150
Merge branch 'develop' into feature/programming-exercises/add-affecte…
az108 Nov 14, 2024
4594289
ramona feedback
az108 Nov 14, 2024
6fa20f9
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Nov 14, 2024
7d1b039
server style
az108 Nov 14, 2024
a8f17b7
communication feature added
az108 Nov 16, 2024
bee159f
Merge remote-tracking branch 'origin/develop' into feature/programmin…
az108 Nov 16, 2024
8795e5e
tests added
az108 Nov 17, 2024
60b0ff3
Merge remote-tracking branch 'origin/develop' into feature/programmin…
az108 Nov 17, 2024
45835c4
added translation field
az108 Nov 17, 2024
71a4cdb
server style
az108 Nov 17, 2024
31fa70e
removed functionality for non communication courses
az108 Nov 18, 2024
319b1ca
added missing translation and testfix
az108 Nov 18, 2024
7233d3c
flo feedback
az108 Nov 19, 2024
5d944d7
flo feedback
az108 Nov 19, 2024
bf0611e
flo feedback
az108 Nov 19, 2024
edd9ffd
Merge branch 'develop' into feature/programming-exercises/add-communi…
az108 Nov 19, 2024
ec4dc71
server style
az108 Nov 19, 2024
ffb4ded
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Nov 19, 2024
32cf023
markus feedback
az108 Nov 19, 2024
23988ca
Merge branch 'develop' into feature/programming-exercises/add-communi…
az108 Nov 19, 2024
fdbc64c
ramona feedback
az108 Nov 25, 2024
8f81d0a
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Nov 25, 2024
d24f50f
Merge branch 'develop' into feature/programming-exercises/add-communi…
az108 Nov 25, 2024
72e849e
translation
az108 Nov 25, 2024
4847f02
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Nov 25, 2024
551c964
refactored
az108 Nov 25, 2024
34a7805
levinstein example
az108 Nov 25, 2024
fc5546e
levinstein example
az108 Nov 26, 2024
0153fbd
levinstein added
az108 Nov 27, 2024
332a8fc
Merge remote-tracking branch 'origin/develop' into feature/programmin…
az108 Nov 27, 2024
53d4032
tests
az108 Nov 27, 2024
dbcf03d
change implementation of detailtext to string
az108 Nov 30, 2024
0ea5d26
implementation first draft with levenshtein
az108 Nov 30, 2024
2c559fc
implementation levenshtein
az108 Nov 30, 2024
83c986e
icon colour updated
az108 Nov 30, 2024
deed6fa
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Nov 30, 2024
1702e7a
documentation update
az108 Nov 30, 2024
a1f60af
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Nov 30, 2024
cdf3f38
studentparticipation merged
az108 Nov 30, 2024
873f880
studentparticipation merged
az108 Nov 30, 2024
ee7e9a1
raffi feedback
az108 Nov 30, 2024
025cd07
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Nov 30, 2024
1a0a907
raffi feedback
az108 Dec 1, 2024
d363283
simon feedback
az108 Dec 2, 2024
b157de6
simon feedback
az108 Dec 2, 2024
2a5709c
simon feedback
az108 Dec 2, 2024
4acb80e
simon feedback
az108 Dec 2, 2024
9df1533
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Dec 2, 2024
458bbec
ramona feedback
az108 Dec 3, 2024
56f4cf3
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Dec 3, 2024
bea4e3b
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Dec 4, 2024
783ee73
server style
az108 Dec 4, 2024
c2ce687
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Dec 4, 2024
d8e87c8
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Dec 9, 2024
33bb40c
server test
az108 Dec 10, 2024
ace46ee
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Dec 10, 2024
f806050
server test
az108 Dec 10, 2024
24d88da
renamed variables
az108 Dec 10, 2024
c8263de
renamed variables
az108 Dec 10, 2024
9ae990f
renamed variables
az108 Dec 10, 2024
7b1ae82
renamed variables
az108 Dec 10, 2024
85fad28
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Dec 10, 2024
ccf1d27
renamed variables
az108 Dec 10, 2024
9d0afee
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Dec 10, 2024
7a9173e
reworked affected students
az108 Dec 11, 2024
962aee5
reworked affected students
az108 Dec 11, 2024
c363d1b
revert
az108 Dec 11, 2024
24e2c3a
removed unnecessary overhead
az108 Dec 11, 2024
39936c3
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Dec 11, 2024
aed9401
client test
az108 Dec 11, 2024
8375394
Merge remote-tracking branch 'origin/feature/programming-exercises/ad…
az108 Dec 11, 2024
56fb11b
markus feedback
az108 Dec 12, 2024
80a43dd
markus feedback
az108 Dec 12, 2024
9492208
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Dec 12, 2024
af0c83f
Merge branch 'develop' into feature/programming-exercises/add-groupin…
az108 Dec 17, 2024
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
@@ -1,4 +1,4 @@
package de.tum.cit.aet.artemis.assessment.dto;

public record FeedbackAffectedStudentDTO(long courseId, long participationId, String firstName, String lastName, String login, String repositoryURI) {
public record FeedbackAffectedStudentDTO(long participationId, String firstName, String lastName, String login, String repositoryURI) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record FeedbackAnalysisResponseDTO(SearchResultPageDTO<FeedbackDetailDTO> feedbackDetails, long totalItems, Set<String> taskNames, List<String> testCaseNames,
List<String> errorCategories) {
List<String> errorCategories, long highestOccurrenceOfGroupedFeedback) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record FeedbackDetailDTO(List<Long> concatenatedFeedbackIds, long count, double relativeCount, String detailText, String testCaseName, String taskName,
String errorCategory) {
public record FeedbackDetailDTO(List<Long> feedbackIds, long count, double relativeCount, List<String> detailTexts, String testCaseName, String taskName, String errorCategory) {

public FeedbackDetailDTO(String concatenatedFeedbackIds, long count, double relativeCount, String detailText, String testCaseName, String taskName, String errorCategory) {
this(Arrays.stream(concatenatedFeedbackIds.split(",")).map(Long::valueOf).toList(), count, relativeCount, detailText, testCaseName, taskName, errorCategory);
public FeedbackDetailDTO(String feedbackId, long count, double relativeCount, String detailText, String testCaseName, String taskName, String errorCategory) {
// Feedback IDs are gathered in the query using a comma separator, and the detail texts are stored in a list because, in case aggregation is applied, the detail texts are
// grouped together
this(Arrays.stream(feedbackId.split(",")).map(Long::valueOf).toList(), count, relativeCount, List.of(detailText), testCaseName, taskName, errorCategory);
}

}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -23,7 +24,6 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -39,7 +39,6 @@
import de.tum.cit.aet.artemis.core.domain.Course;
import de.tum.cit.aet.artemis.core.domain.User;
import de.tum.cit.aet.artemis.core.dto.SearchResultPageDTO;
import de.tum.cit.aet.artemis.core.dto.pageablesearch.PageableSearchDTO;
import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException;
import de.tum.cit.aet.artemis.core.repository.UserRepository;
import de.tum.cit.aet.artemis.core.security.Role;
Expand Down Expand Up @@ -297,7 +296,7 @@ public ResponseEntity<Result> createResultForExternalSubmission(@PathVariable Lo
* Pagination, sorting, and filtering options allow flexible data retrieval:
* <ul>
* <li><b>Pagination:</b> Based on page number and page size, as specified in the request.</li>
* <li><b>Sorting:</b> By column (e.g., "count" or "detailText") and sorting order (ASCENDING or DESCENDING).
* <li><b>Sorting:</b> By column (e.g., "count" or "detailTexts") and sorting order (ASCENDING or DESCENDING).
* If the specified column is not valid for sorting, the default sorting column is "count".</li>
* <li><b>Filtering:</b>
* <ul>
Expand All @@ -310,18 +309,19 @@ public ResponseEntity<Result> createResultForExternalSubmission(@PathVariable Lo
* </li>
* </ul>
*
* @param exerciseId The unique identifier of the exercise for which feedback details are requested.
* @param data A {@link FeedbackPageableDTO} object containing pagination, sorting, and filtering parameters, including:
* <ul>
* <li>Page number and page size</li>
* <li>Search term (optional)</li>
* <li>Sorting order (ASCENDING or DESCENDING)</li>
* <li>Sorted column</li>
* <li>Filter task names (optional)</li>
* <li>Filter test case names (optional)</li>
* <li>Occurrence range (optional)</li>
* <li>Error categories (optional)</li>
* </ul>
* @param exerciseId The unique identifier of the exercise for which feedback details are requested.
* @param groupFeedback Should the feedback be grouped
* @param data A {@link FeedbackPageableDTO} object containing pagination, sorting, and filtering parameters, including:
* <ul>
* <li>Page number and page size</li>
* <li>Search term (optional)</li>
* <li>Sorting order (ASCENDING or DESCENDING)</li>
* <li>Sorted column</li>
* <li>Filter task names (optional)</li>
* <li>Filter test case names (optional)</li>
* <li>Occurrence range (optional)</li>
* <li>Error categories (optional)</li>
* </ul>
* @return A {@link ResponseEntity} containing a {@link FeedbackAnalysisResponseDTO}, which includes:
* <ul>
* <li>{@link SearchResultPageDTO < FeedbackDetailDTO >} feedbackDetails: Paginated and filtered feedback details for the exercise.</li>
Expand All @@ -333,8 +333,9 @@ public ResponseEntity<Result> createResultForExternalSubmission(@PathVariable Lo
*/
@GetMapping("exercises/{exerciseId}/feedback-details")
@EnforceAtLeastEditorInExercise
public ResponseEntity<FeedbackAnalysisResponseDTO> getFeedbackDetailsPaged(@PathVariable long exerciseId, @ModelAttribute FeedbackPageableDTO data) {
FeedbackAnalysisResponseDTO response = resultService.getFeedbackDetailsOnPage(exerciseId, data);
public ResponseEntity<FeedbackAnalysisResponseDTO> getFeedbackDetailsPaged(@PathVariable long exerciseId, @RequestParam("groupFeedback") boolean groupFeedback,
az108 marked this conversation as resolved.
Show resolved Hide resolved
@ModelAttribute FeedbackPageableDTO data) {
FeedbackAnalysisResponseDTO response = resultService.getFeedbackDetailsOnPage(exerciseId, data, groupFeedback);
return ResponseEntity.ok(response);
}

Expand All @@ -359,32 +360,24 @@ public ResponseEntity<Long> getMaxCount(@PathVariable long exerciseId) {
* and participation details.
* <br>
*
* @param exerciseId for which the participation data is requested.
* @param feedbackIdsHeader to filter affected students by specific feedback entries.
* @param data A {@link PageableSearchDTO} object containing pagination and sorting parameters.
* @return A {@link ResponseEntity} containing a {@link Page} of {@link FeedbackAffectedStudentDTO}, each representing a student affected by the feedback entries.
* @param exerciseId for which the participation data is requested.
* @param feedbackId1 Optional first detail text id to filter affected students by specific feedback entries.
* @param feedbackId2 Optional second detail text id to filter affected students by specific feedback entries.
* @param feedbackId3 Optional third detail text id to filter affected students by specific feedback entries.
* @param feedbackId4 Optional fourth detail text id to filter affected students by specific feedback entries.
* @param feedbackId5 Optional fifth detail text id to filter affected students by specific feedback entries.
* @return A {@link ResponseEntity} containing a {@link List} of {@link FeedbackAffectedStudentDTO}, each representing a student affected by the feedback entries.
*/
@GetMapping("exercises/{exerciseId}/feedback-details-participation")
@EnforceAtLeastEditorInExercise
public ResponseEntity<Page<FeedbackAffectedStudentDTO>> getAffectedStudentsWithFeedback(@PathVariable long exerciseId, @RequestHeader("feedbackIds") String feedbackIdsHeader,
@ModelAttribute PageableSearchDTO<String> data) {
public ResponseEntity<List<FeedbackAffectedStudentDTO>> getAffectedStudentsWithFeedback(@PathVariable long exerciseId,
@RequestParam(value = "feedbackId1", required = false) Long feedbackId1, @RequestParam(value = "feedbackId2", required = false) Long feedbackId2,
@RequestParam(value = "feedbackId3", required = false) Long feedbackId3, @RequestParam(value = "feedbackId4", required = false) Long feedbackId4,
@RequestParam(value = "feedbackId5", required = false) Long feedbackId5) {

Page<FeedbackAffectedStudentDTO> participation = resultService.getAffectedStudentsWithFeedbackId(exerciseId, feedbackIdsHeader, data);
List<Long> feedbackIds = Stream.of(feedbackId1, feedbackId2, feedbackId3, feedbackId4, feedbackId5).filter(Objects::nonNull).toList();

List<FeedbackAffectedStudentDTO> participation = resultService.getAffectedStudentsWithFeedbackIds(exerciseId, feedbackIds);
return ResponseEntity.ok(participation);
}

/**
* GET /exercises/{exerciseId}/feedback-detail/affected-students : Retrieves the count of students affected by a specific feedback detail text.
*
* @param exerciseId The ID of the exercise for which affected students are counted.
* @param detailText The feedback detail text to filter by.
* @return A {@link ResponseEntity} containing the count of affected students.
*/
@GetMapping("exercises/{exerciseId}/feedback-detail/affected-students")
@EnforceAtLeastEditorInExercise
public ResponseEntity<Long> countAffectedStudentsByFeedbackDetailText(@PathVariable long exerciseId, @RequestParam("detailText") String detailText) {
long affectedStudentCount = resultService.getAffectedStudentCountByFeedbackDetailText(exerciseId, detailText);
return ResponseEntity.ok(affectedStudentCount);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package de.tum.cit.aet.artemis.communication.dto;

import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record FeedbackChannelRequestDTO(ChannelDTO channel, String feedbackDetailText) {
public record FeedbackChannelRequestDTO(ChannelDTO channel, List<String> feedbackDetailTexts, String testCaseName) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -418,15 +418,16 @@ private static String generateChannelNameFromTitle(@NotNull String prefix, Optio
/**
* Creates a feedback-specific channel for an exercise within a course.
*
* @param course in which the channel is being created.
* @param exerciseId of the exercise associated with the feedback channel.
* @param channelDTO containing the properties of the channel to be created, such as name, description, and visibility.
* @param feedbackDetailText used to identify the students affected by the feedback.
* @param requestingUser initiating the channel creation request.
* @param course in which the channel is being created.
* @param exerciseId of the exercise associated with the feedback channel.
* @param channelDTO containing the properties of the channel to be created, such as name, description, and visibility.
* @param feedbackDetailTexts used to identify the students affected by the feedback.
* @param requestingUser initiating the channel creation request.
* @param testCaseName to filter student submissions according to a specific feedback
* @return the created {@link Channel} object with its properties.
* @throws BadRequestAlertException if the channel name starts with an invalid prefix (e.g., "$").
*/
public Channel createFeedbackChannel(Course course, Long exerciseId, ChannelDTO channelDTO, String feedbackDetailText, User requestingUser) {
public Channel createFeedbackChannel(Course course, Long exerciseId, ChannelDTO channelDTO, List<String> feedbackDetailTexts, String testCaseName, User requestingUser) {
Channel channelToCreate = new Channel();
channelToCreate.setName(channelDTO.getName());
channelToCreate.setIsPublic(channelDTO.getIsPublic());
Expand All @@ -440,7 +441,7 @@ public Channel createFeedbackChannel(Course course, Long exerciseId, ChannelDTO

Channel createdChannel = createChannel(course, channelToCreate, Optional.of(requestingUser));

List<String> userLogins = studentParticipationRepository.findAffectedLoginsByFeedbackDetailText(exerciseId, feedbackDetailText);
List<String> userLogins = studentParticipationRepository.findAffectedLoginsByFeedbackDetailText(exerciseId, feedbackDetailTexts, testCaseName);

if (userLogins != null && !userLogins.isEmpty()) {
var registeredUsers = registerUsersToChannel(false, false, false, userLogins, course, createdChannel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,12 +486,13 @@ public ResponseEntity<ChannelDTO> createFeedbackChannel(@PathVariable Long cours
log.debug("REST request to create feedback channel for course {} and exercise {} with properties: {}", courseId, exerciseId, feedbackChannelRequest);

ChannelDTO channelDTO = feedbackChannelRequest.channel();
String feedbackDetailText = feedbackChannelRequest.feedbackDetailText();
List<String> feedbackDetailTexts = feedbackChannelRequest.feedbackDetailTexts();
String testCaseName = feedbackChannelRequest.testCaseName();

User requestingUser = userRepository.getUserWithGroupsAndAuthorities();
Course course = courseRepository.findByIdElseThrow(courseId);
checkCommunicationEnabledElseThrow(course);
Channel createdChannel = channelService.createFeedbackChannel(course, exerciseId, channelDTO, feedbackDetailText, requestingUser);
Channel createdChannel = channelService.createFeedbackChannel(course, exerciseId, channelDTO, feedbackDetailTexts, testCaseName, requestingUser);

return ResponseEntity.created(new URI("/api/channels/" + createdChannel.getId())).body(conversationDTOService.convertChannelToDTO(requestingUser, createdChannel));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public enum ColumnMapping {
)),
FEEDBACK_ANALYSIS(Map.of(
"count", "COUNT(f.id)",
"detailText", "f.detailText",
"detailTexts", "f.detailText",
az108 marked this conversation as resolved.
Show resolved Hide resolved
"testCaseName", "f.testCase.testName",
"taskName", """
COALESCE((
Expand All @@ -82,9 +82,6 @@ SELECT MAX(t.taskName)
JOIN t.testCases tct
WHERE t.exercise.id = :exerciseId AND tct.testName = f.testCase.testName
), '')"""
)),
AFFECTED_STUDENTS(Map.of(
"participationId", "p.id"
));
// @formatter:on

Expand Down
Loading
Loading