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: Fix an issue with access tokens for team exercises #9802

Merged
merged 7 commits into from
Nov 24, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

import de.tum.cit.aet.artemis.core.domain.User;
import de.tum.cit.aet.artemis.core.exception.AccessForbiddenException;
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.repository.TeamRepository;
import de.tum.cit.aet.artemis.programming.domain.ParticipationVCSAccessToken;
import de.tum.cit.aet.artemis.programming.repository.ParticipationVCSAccessTokenRepository;
import de.tum.cit.aet.artemis.programming.repository.ProgrammingExerciseStudentParticipationRepository;
Expand All @@ -25,10 +27,13 @@ public class ParticipationVcsAccessTokenService {

private final ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository;

private final TeamRepository teamRepository;

public ParticipationVcsAccessTokenService(ParticipationVCSAccessTokenRepository participationVCSAccessTokenRepository,
ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository) {
ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository, TeamRepository teamRepository) {
this.participationVcsAccessTokenRepository = participationVCSAccessTokenRepository;
this.programmingExerciseStudentParticipationRepository = programmingExerciseStudentParticipationRepository;
this.teamRepository = teamRepository;
}

/**
Expand All @@ -55,6 +60,7 @@ public ParticipationVCSAccessToken createParticipationVCSAccessToken(User user,
*/
public ParticipationVCSAccessToken findByUserAndParticipationIdOrElseThrow(User user, long participationId) {
var participation = programmingExerciseStudentParticipationRepository.findByIdElseThrow(participationId);
loadTeamStudentsForTeamExercise(participation);
if (participation.isOwnedBy(user)) {
return participationVcsAccessTokenRepository.findByUserIdAndParticipationIdOrElseThrow(user.getId(), participationId);
}
Expand All @@ -73,6 +79,7 @@ public ParticipationVCSAccessToken findByUserAndParticipationIdOrElseThrow(User
public ParticipationVCSAccessToken createVcsAccessTokenForUserAndParticipationIdOrElseThrow(User user, long participationId) {
participationVcsAccessTokenRepository.findByUserIdAndParticipationIdAndThrowIfExists(user.getId(), participationId);
var participation = programmingExerciseStudentParticipationRepository.findByIdElseThrow(participationId);
loadTeamStudentsForTeamExercise(participation);
krusche marked this conversation as resolved.
Show resolved Hide resolved
if (participation.isOwnedBy(user)) {
return createParticipationVCSAccessToken(user, participation);
}
Expand All @@ -81,6 +88,19 @@ public ParticipationVCSAccessToken createVcsAccessTokenForUserAndParticipationId
}
}

/**
* Loads the team students of a participation's team, if it has a team
*
* @param participation the participation which team's students are not loaded yet
*/
private void loadTeamStudentsForTeamExercise(StudentParticipation participation) {
if (participation.getTeam().isPresent()) {
Team team = participation.getTeam().get();
Team teamWithStudents = teamRepository.findWithStudentsByIdElseThrow(team.getId());
participation.getTeam().get().setStudents(teamWithStudents.getStudents());
}
}
SimonEntholzer marked this conversation as resolved.
Show resolved Hide resolved

/**
* Deletes the token connected to a participation
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ void getAndCreateParticipationVcsAccessTokenByUser() throws Exception {
userTestService.getAndCreateParticipationVcsAccessToken();
}

@Test
@WithMockUser(username = TEST_PREFIX + "student1", roles = "USER")
void getParticipationVcsAccessTokenByUserForTeamExercise() throws Exception {
userTestService.getAndCreateParticipationVcsAccessTokenForTeamExercise();
}

@Test
@WithMockUser(username = TEST_PREFIX + "student1", roles = "USER")
void createAndDeleteUserVcsAccessTokenByUser() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@
import de.tum.cit.aet.artemis.core.test_repository.UserTestRepository;
import de.tum.cit.aet.artemis.core.util.CourseUtilService;
import de.tum.cit.aet.artemis.core.util.RequestUtilService;
import de.tum.cit.aet.artemis.exercise.domain.ExerciseMode;
import de.tum.cit.aet.artemis.exercise.domain.SubmissionType;
import de.tum.cit.aet.artemis.exercise.domain.Team;
import de.tum.cit.aet.artemis.exercise.repository.ExerciseTestRepository;
import de.tum.cit.aet.artemis.exercise.team.TeamUtilService;
import de.tum.cit.aet.artemis.exercise.test_repository.ParticipationTestRepository;
import de.tum.cit.aet.artemis.exercise.test_repository.SubmissionTestRepository;
import de.tum.cit.aet.artemis.lti.service.LtiService;
Expand Down Expand Up @@ -91,6 +95,9 @@ public class UserTestService {
@Autowired
private UserUtilService userUtilService;

@Autowired
private TeamUtilService teamUtilService;

@Autowired
private CourseUtilService courseUtilService;

Expand Down Expand Up @@ -128,6 +135,9 @@ public class UserTestService {
@Autowired
private SubmissionTestRepository submissionRepository;

@Autowired
private ExerciseTestRepository exerciseTestRepository;

public void setup(String testPrefix, MockDelegate mockDelegate) throws Exception {
this.TEST_PREFIX = testPrefix;
this.mockDelegate = mockDelegate;
Expand Down Expand Up @@ -915,6 +925,36 @@ public void getAndCreateParticipationVcsAccessToken() throws Exception {
participationRepository.deleteById(submission.getParticipation().getId());
}

// Test
public void getAndCreateParticipationVcsAccessTokenForTeamExercise() throws Exception {
SimonEntholzer marked this conversation as resolved.
Show resolved Hide resolved
User user = userUtilService.getUserByLogin(TEST_PREFIX + "student1");
var course = courseUtilService.addEmptyCourse();
var exercise = programmingExerciseUtilService.addProgrammingExerciseToCourse(course);
exercise.setMode(ExerciseMode.TEAM);
exerciseTestRepository.save(exercise);
courseRepository.save(course);
User tutor1 = userTestRepository.findOneByLogin(TEST_PREFIX + "tutor1").orElseThrow();
Team team = teamUtilService.createTeam(Set.of(user), tutor1, exercise, "team1");

var submission = (ProgrammingSubmission) new ProgrammingSubmission().commitHash("abc").type(SubmissionType.MANUAL).submitted(true);
submission = programmingExerciseUtilService.addProgrammingSubmissionToTeamExercise(exercise, submission, team);

// request existing token
request.get("/api/account/participation-vcs-access-token?participationId=" + submission.getParticipation().getId(), HttpStatus.NOT_FOUND, String.class);

var token = request.putWithResponseBody("/api/account/participation-vcs-access-token?participationId=" + submission.getParticipation().getId(), null, String.class,
HttpStatus.OK);
assertThat(token).isNotNull();

var token2 = request.get("/api/account/participation-vcs-access-token?participationId=" + submission.getParticipation().getId(), HttpStatus.OK, String.class);
assertThat(token2).isEqualTo(token);

submissionRepository.delete(submission);
participationVCSAccessTokenRepository.deleteAll();
participationRepository.deleteById(submission.getParticipation().getId());
teamUtilService.deleteTeam(team);
}

// Test
public void createAndDeleteUserVcsAccessToken() throws Exception {
User user = userUtilService.getUserByLogin(TEST_PREFIX + "student1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,8 @@ public Team createTeam(Set<User> students, User owner, Exercise exercise, String
team.setExercise(exercise);
return teamRepo.saveAndFlush(team);
}

public void deleteTeam(Team team) {
teamRepo.delete(team);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import de.tum.cit.aet.artemis.exam.util.ExamUtilService;
import de.tum.cit.aet.artemis.exercise.domain.InitializationState;
import de.tum.cit.aet.artemis.exercise.domain.SubmissionType;
import de.tum.cit.aet.artemis.exercise.domain.Team;
import de.tum.cit.aet.artemis.exercise.domain.participation.Participation;
import de.tum.cit.aet.artemis.exercise.domain.participation.StudentParticipation;
import de.tum.cit.aet.artemis.exercise.participation.util.ParticipationFactory;
Expand Down Expand Up @@ -741,6 +742,21 @@ public ProgrammingSubmission addProgrammingSubmission(ProgrammingExercise exerci
return submission;
}

/**
* Adds programming submission to provided programming exercise. The provided login is used to access or create a participation.
*
* @param exercise The exercise to which the submission should be added.
* @param submission The submission which should be added to the programming exercise.
* @param team The login of the user used to access or create an exercise participation.
* @return The created programming submission.
*/
public ProgrammingSubmission addProgrammingSubmissionToTeamExercise(ProgrammingExercise exercise, ProgrammingSubmission submission, Team team) {
StudentParticipation participation = participationUtilService.addTeamParticipationForProgrammingExercise(exercise, team);
submission.setParticipation(participation);
submission = programmingSubmissionRepo.save(submission);
return submission;
}

/**
* Adds a submission with a result to the given programming exercise. The submission will be assigned to the corresponding participation of the given login (if exists or
* create a new participation).
Expand Down
Loading