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 @@ -78,6 +78,20 @@ public List<ProactiveFeedback> allProactiveFeedback(
.toList();
}

/**
* Retrieves the latest proactive feedback for the current user.
* The feedback is deleted after retrieval and must be less than 30 minutes old.
*
* @param currentUser the currently logged-in user
* @return feedback text if available, otherwise null
*/
@QueryMapping
public String latestProactiveFeedback(
@ContextValue final LoggedInUser currentUser
) {
return tutorService.getLatestProactiveFeedback(currentUser).orElse(null);
}

/**
* GraphQL subscription for real-time proactive feedback.
* Frontend subscribes to this and receives feedback automatically when generated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,25 +69,14 @@ public class TutorService {
/**
* Handles a user’s question by categorizing it and returning an appropriate response.
* Lecture questions are further processed, while other categories currently return default answers.
* Special handling: if the user input is "proactivefeedback", retrieves and deletes the latest saved feedback for the user.

*
* @param userQuestion the question asked by the user
* @param courseId the ID of the course, required for lecture-related questions
* @param currentUser the currently logged-in user
* @return a response object containing the answer or a default message
*/
public LectureQuestionResponse handleUserQuestion(String userQuestion, UUID courseId, LoggedInUser currentUser){

// Special handling for proactive feedback retrieval. Will be removed once proactive feedback is integrated into the main flow and graphql works correctly.
if ("proactivefeedback".equalsIgnoreCase(userQuestion.trim())) {
Optional<String> feedback = proactiveFeedbackService.getAndDeleteLatestFeedback(currentUser.getId());
if (feedback.isPresent()) {
return new LectureQuestionResponse(feedback.get(), List.of());
} else {
return new LectureQuestionResponse("No proactive feedback available at the moment.", List.of());
}
}

log.info("[TUTOR] User {} asked question: {}", currentUser.getId(), userQuestion);

CategorizedQuestion categorizedQuestion = preprocessQuestion(userQuestion);
Expand Down Expand Up @@ -124,6 +113,17 @@ public LectureQuestionResponse handleUserQuestion(String userQuestion, UUID cour
return new LectureQuestionResponse(ERROR_MESSAGE, List.of());
}

/**
* Retrieves the latest proactive feedback for the given user.
* The feedback is deleted after retrieval and must be less than 30 minutes old.
*
* @param currentUser the currently logged-in user
* @return optional containing feedback text if available, otherwise empty
*/
public Optional<String> getLatestProactiveFeedback(LoggedInUser currentUser) {
return proactiveFeedbackService.getAndDeleteLatestFeedback(currentUser.getId());
}

private LectureQuestionResponse answerLectureQuestion(String question, UUID courseId, LoggedInUser currentUser){
Optional<HexadPlayerType> playerType = userPlayerTypeService.getPrimaryPlayerType(currentUser.getId());

Expand Down
7 changes: 7 additions & 0 deletions src/main/resources/graphql/service/query.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@ type Query {
Retrieves all proactive feedback for the current user, ordered by most recent first.
"""
allProactiveFeedback: [ProactiveFeedback!]!

"""
Retrieves the latest proactive feedback for the current user (any assessment).
The feedback is deleted after retrieval and must be less than 30 minutes old.
Returns the feedback text or null if no feedback is available.
"""
latestProactiveFeedback: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,28 @@ void testAllProactiveFeedback_empty() {
assertTrue(result.isEmpty());
}

@Test
void testLatestProactiveFeedback_withFeedback() {
String feedback = "Great job on your assignment!";
when(tutorService.getLatestProactiveFeedback(loggedInUser))
.thenReturn(Optional.of(feedback));

String result = tutorController.latestProactiveFeedback(loggedInUser);

assertEquals(feedback, result);
verify(tutorService).getLatestProactiveFeedback(loggedInUser);
}

@Test
void testLatestProactiveFeedback_noFeedback() {
when(tutorService.getLatestProactiveFeedback(loggedInUser))
.thenReturn(Optional.empty());

String result = tutorController.latestProactiveFeedback(loggedInUser);

assertNull(result);
}

@Test
void testProactiveFeedbackAdded_subscription() {
UUID userId = UUID.randomUUID();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import static de.unistuttgart.iste.meitrex.common.testutil.TestUsers.userWithMembershipInCourseWithId;
import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;

public class TutorServiceTest {

Expand Down Expand Up @@ -209,23 +211,24 @@ void testHandleUserQuestion_withCodeFeedbackNoSubmissions() {
}

@Test
void testHandleUserQuestion_withProactiveFeedbackKeyword() {
void testGetLatestProactiveFeedback_withFeedback() {
String feedback = "Great job on your assignment!";
when(proactiveFeedbackService.getAndDeleteLatestFeedback(loggedInUser.getId()))
.thenReturn(Optional.of(feedback));

LectureQuestionResponse response = tutorService.handleUserQuestion("proactivefeedback", courseId, loggedInUser);
assertEquals(feedback, response.getAnswer());
Optional<String> response = tutorService.getLatestProactiveFeedback(loggedInUser);
assertTrue(response.isPresent());
assertEquals(feedback, response.get());
Mockito.verify(proactiveFeedbackService).getAndDeleteLatestFeedback(loggedInUser.getId());
}

@Test
void testHandleUserQuestion_withProactiveFeedbackKeywordNoFeedback() {
void testGetLatestProactiveFeedback_withNoFeedback() {
when(proactiveFeedbackService.getAndDeleteLatestFeedback(loggedInUser.getId()))
.thenReturn(Optional.empty());

LectureQuestionResponse response = tutorService.handleUserQuestion("proactivefeedback", courseId, loggedInUser);
assertEquals("No proactive feedback available at the moment.", response.getAnswer());
Optional<String> response = tutorService.getLatestProactiveFeedback(loggedInUser);
assertFalse(response.isPresent());
}

@Test
Expand Down
Loading