Skip to content

Commit 9cc16c8

Browse files
committed
Bugfix: No longer sends multiple StudentCodeSubmittedEvents on page reload
1 parent e03eb1b commit 9cc16c8

6 files changed

Lines changed: 58 additions & 34 deletions

File tree

src/main/java/de/unistuttgart/iste/meitrex/assignment_service/persistence/entity/grading/CodeAssignmentGradingMetadataEntity.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,7 @@ public class CodeAssignmentGradingMetadataEntity {
3737

3838
@Column(nullable = true, columnDefinition = "TEXT")
3939
private String feedbackTableHtml;
40+
41+
@Column(nullable = true)
42+
private String lastProcessedCommitSha;
4043
}

src/main/java/de/unistuttgart/iste/meitrex/assignment_service/service/GradingService.java

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -250,20 +250,47 @@ private List<Grading> getCodeAssignmentGradingForStudent(final AssignmentEntity
250250
assignment.setTotalCredits(externalGrading.totalPoints());
251251
}
252252

253-
try {
254-
if (codeAssessmentProvider instanceof de.unistuttgart.iste.meitrex.assignment_service.service.code_assignment.GithubClassroom githubClassroom) {
255-
de.unistuttgart.iste.meitrex.assignment_service.service.code_assignment.StudentCodeSubmission codeSubmission =
256-
githubClassroom.fetchStudentCode(gradingEntity.getCodeAssignmentGradingMetadata().getRepoLink(), currentUser);
257-
258-
259-
codeSubmission.setAssignmentId(assignment.getId());
260-
codeSubmission.setCourseId(assignment.getCourseId());
261-
262-
publishStudentCodeSubmittedEvent(codeSubmission);
253+
String lastProcessedCommit = metadata.getLastProcessedCommitSha();
254+
String currentCommit = externalGrading.commitSha();
255+
boolean shouldSendEvent = false;
256+
257+
if (currentCommit != null) {
258+
if (lastProcessedCommit == null || lastProcessedCommit.equals("NO_COMMIT_SHA_PROCESSED")) {
259+
shouldSendEvent = true;
260+
} else if (!currentCommit.equals(lastProcessedCommit)) {
261+
shouldSendEvent = true;
262+
} else {
263+
log.debug("Skipping code submission event. Commit {} already processed for student {} on assignment {}",
264+
currentCommit, currentUser.getId(), assignment.getId());
265+
}
266+
} else {
267+
if (lastProcessedCommit == null || lastProcessedCommit.equals("NO_COMMIT_SHA_PROCESSED")) {
268+
shouldSendEvent = true;
269+
log.warn("No commit SHA available for assignment {} and student {}, sending event without commit tracking",
270+
assignment.getId(), currentUser.getId());
271+
} else {
272+
log.debug("No commit SHA and event already sent once for student {} on assignment {}, skipping",
273+
currentUser.getId(), assignment.getId());
274+
}
275+
}
276+
277+
if (shouldSendEvent) {
278+
try {
279+
if (codeAssessmentProvider instanceof de.unistuttgart.iste.meitrex.assignment_service.service.code_assignment.GithubClassroom githubClassroom) {
280+
de.unistuttgart.iste.meitrex.assignment_service.service.code_assignment.StudentCodeSubmission codeSubmission =
281+
githubClassroom.fetchStudentCode(gradingEntity.getCodeAssignmentGradingMetadata().getRepoLink(), currentUser);
282+
283+
codeSubmission.setAssignmentId(assignment.getId());
284+
codeSubmission.setCourseId(assignment.getCourseId());
285+
286+
publishStudentCodeSubmittedEvent(codeSubmission);
287+
288+
metadata.setLastProcessedCommitSha(currentCommit != null ? currentCommit : "NO_COMMIT_SHA_PROCESSED");
289+
}
290+
} catch (ExternalPlatformConnectionException | UserServiceConnectionException e) {
291+
log.error("Failed to fetch student code for assignment {} and student {}: {}",
292+
assignment.getId(), currentUser.getId(), e.toString());
263293
}
264-
} catch (ExternalPlatformConnectionException | UserServiceConnectionException e) {
265-
log.error("Failed to fetch student code for assignment {} and student {}: {}",
266-
assignment.getId(), currentUser.getId(), e.toString());
267294
}
268295
}
269296

src/main/java/de/unistuttgart/iste/meitrex/assignment_service/service/code_assignment/ExternalGrading.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,12 @@
22

33
import java.time.OffsetDateTime;
44

5-
public record ExternalGrading(String externalUsername, String status, OffsetDateTime date, String tableHtml, Double achievedPoints, Double totalPoints) {
5+
public record ExternalGrading(
6+
String externalUsername,
7+
String status,
8+
OffsetDateTime date,
9+
String tableHtml,
10+
Double achievedPoints,
11+
Double totalPoints,
12+
String commitSha) {
613
}

src/main/java/de/unistuttgart/iste/meitrex/assignment_service/service/code_assignment/GithubClassroom.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ public List<ExternalGrading> syncGrades(final String externalAssignmentId, final
280280
}
281281
}
282282

283-
gradings.add(new ExternalGrading(username, null, submissionDate, null, achieved, total));
283+
gradings.add(new ExternalGrading(username, null, submissionDate, null, achieved, total, null));
284284
}
285285

286286
return gradings;
@@ -333,9 +333,10 @@ public ExternalGrading syncGradeForStudent(String repoLink, LoggedInUser current
333333
String status = run.get("status").getAsString();
334334
String logsUrl = run.get("logs_url").getAsString();
335335
String lastlyTested = run.get("updated_at").getAsString();
336+
String commitSha = run.has("head_sha") ? run.get("head_sha").getAsString() : null;
336337

337338
if (!status.equals("completed")){
338-
return new ExternalGrading(null, status, OffsetDateTime.parse(lastlyTested), null, null, null);
339+
return new ExternalGrading(null, status, OffsetDateTime.parse(lastlyTested), null, null, null, commitSha);
339340
}
340341

341342
// Download logs
@@ -377,7 +378,7 @@ public ExternalGrading syncGradeForStudent(String repoLink, LoggedInUser current
377378
double totalPoints = Double.parseDouble(matcher.group(1));
378379
double maxPoints = Double.parseDouble(matcher.group(2));
379380
String tableHtml = extractGradingTableAsHtml(logs);
380-
return new ExternalGrading(null, status, OffsetDateTime.parse(lastlyTested), tableHtml, totalPoints, maxPoints);
381+
return new ExternalGrading(null, status, OffsetDateTime.parse(lastlyTested), tableHtml, totalPoints, maxPoints, commitSha);
381382
} else {
382383
throw new ExternalPlatformConnectionException("Could not find totalPoints/maxPoints in logs.");
383384
}

src/test/java/de/unistuttgart/iste/meitrex/assignment_service/api/QueryGetCodeGradingForAssignmentForStudentTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ void testStudentGetsCodeAssignmentGradingSynced(GraphQlTester tester) throws Ext
116116
);
117117

118118
ExternalGrading externalGrading = new ExternalGrading("ext-user", gradingEntity.getCodeAssignmentGradingMetadata().getRepoLink(), OffsetDateTime.now(),
119-
"<table>feedback</table>", 42.0, 60.0);
119+
"<table>feedback</table>", 42.0, 60.0, "test-commit-sha");
120120

121121
when(codeAssessmentProvider.findRepository(eq(assignment.getExternalId()), any(), any())).thenReturn(gradingEntity.getCodeAssignmentGradingMetadata().getRepoLink());
122122

@@ -227,7 +227,8 @@ void testStudentGetsCodeAssignmentGradingCreated(GraphQlTester tester)
227227
OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS),
228228
"<table>feedback</table>",
229229
35.0,
230-
50.0
230+
50.0,
231+
"test-commit-sha-2"
231232
);
232233
when(codeAssessmentProvider.syncGradeForStudent(eq("https://github.com/user/repo"), any()))
233234
.thenReturn(externalGrading);

src/test/java/de/unistuttgart/iste/meitrex/assignment_service/service/GradingServiceEventPublishingTest.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,9 @@ void setUp() {
4242

4343
@Test
4444
void testPublishStudentCodeSubmittedEvent_Success() throws Exception {
45-
// Arrange
4645
String repoUrl = "https://github.com/org/repo-student";
4746
StudentCodeSubmission codeSubmission = createMockCodeSubmission(repoUrl);
4847

49-
// Create the event that would be published
5048
StudentCodeSubmittedEvent event = StudentCodeSubmittedEvent.builder()
5149
.studentId(codeSubmission.getStudentId())
5250
.assignmentId(codeSubmission.getAssignmentId())
@@ -58,10 +56,8 @@ void testPublishStudentCodeSubmittedEvent_Success() throws Exception {
5856
.branch(codeSubmission.getBranch())
5957
.build();
6058

61-
// Act
6259
topicPublisher.notifyStudentCodeSubmitted(event);
6360

64-
// Assert
6561
ArgumentCaptor<StudentCodeSubmittedEvent> eventCaptor =
6662
ArgumentCaptor.forClass(StudentCodeSubmittedEvent.class);
6763
verify(topicPublisher, times(1)).notifyStudentCodeSubmitted(eventCaptor.capture());
@@ -80,7 +76,6 @@ void testPublishStudentCodeSubmittedEvent_Success() throws Exception {
8076

8177
@Test
8278
void testCodeSubmissionEventContent_AllFieldsPresent() {
83-
// Arrange
8479
String repoUrl = "https://github.com/test/repo";
8580
String commitSha = "abc123def456";
8681
OffsetDateTime commitTime = OffsetDateTime.now();
@@ -89,7 +84,6 @@ void testCodeSubmissionEventContent_AllFieldsPresent() {
8984
Map<String, String> files = new HashMap<>();
9085
files.put("Test.java", "public class Test {}");
9186

92-
// Act
9387
StudentCodeSubmittedEvent event = StudentCodeSubmittedEvent.builder()
9488
.studentId(studentId)
9589
.assignmentId(assignmentId)
@@ -101,7 +95,6 @@ void testCodeSubmissionEventContent_AllFieldsPresent() {
10195
.branch(branch)
10296
.build();
10397

104-
// Assert
10598
assertEquals(studentId, event.getStudentId());
10699
assertEquals(assignmentId, event.getAssignmentId());
107100
assertEquals(courseId, event.getCourseId());
@@ -114,7 +107,6 @@ void testCodeSubmissionEventContent_AllFieldsPresent() {
114107

115108
@Test
116109
void testCodeSubmission_MultipleFiles() {
117-
// Arrange
118110
StudentCodeSubmission codeSubmission = StudentCodeSubmission.builder()
119111
.studentId(studentId)
120112
.assignmentId(assignmentId)
@@ -126,7 +118,6 @@ void testCodeSubmission_MultipleFiles() {
126118
.files(createMultipleFiles())
127119
.build();
128120

129-
// Act
130121
StudentCodeSubmittedEvent event = StudentCodeSubmittedEvent.builder()
131122
.studentId(codeSubmission.getStudentId())
132123
.assignmentId(codeSubmission.getAssignmentId())
@@ -138,7 +129,6 @@ void testCodeSubmission_MultipleFiles() {
138129
.branch(codeSubmission.getBranch())
139130
.build();
140131

141-
// Assert
142132
assertNotNull(event.getFiles());
143133
assertEquals(5, event.getFiles().size());
144134
assertTrue(event.getFiles().containsKey("src/Main.java"));
@@ -150,7 +140,6 @@ void testCodeSubmission_MultipleFiles() {
150140

151141
@Test
152142
void testCodeSubmission_EmptyFiles() {
153-
// Arrange
154143
StudentCodeSubmission codeSubmission = StudentCodeSubmission.builder()
155144
.studentId(studentId)
156145
.assignmentId(assignmentId)
@@ -162,7 +151,6 @@ void testCodeSubmission_EmptyFiles() {
162151
.files(new HashMap<>())
163152
.build();
164153

165-
// Act
166154
StudentCodeSubmittedEvent event = StudentCodeSubmittedEvent.builder()
167155
.studentId(codeSubmission.getStudentId())
168156
.assignmentId(codeSubmission.getAssignmentId())
@@ -174,14 +162,12 @@ void testCodeSubmission_EmptyFiles() {
174162
.branch(codeSubmission.getBranch())
175163
.build();
176164

177-
// Assert
178165
assertNotNull(event.getFiles());
179166
assertTrue(event.getFiles().isEmpty());
180167
}
181168

182169
@Test
183170
void testCodeSubmission_VerifyMetadata() {
184-
// Arrange
185171
String repoUrl = "https://github.com/student/assignment-repo";
186172
String commitSha = "1234567890abcdef";
187173
OffsetDateTime timestamp = OffsetDateTime.parse("2025-12-15T10:30:00Z");
@@ -198,7 +184,6 @@ void testCodeSubmission_VerifyMetadata() {
198184
.files(Map.of("Main.java", "code"))
199185
.build();
200186

201-
// Assert
202187
assertEquals(repoUrl, submission.getRepositoryUrl());
203188
assertEquals(commitSha, submission.getCommitSha());
204189
assertEquals(timestamp, submission.getCommitTimestamp());

0 commit comments

Comments
 (0)