use of de.tum.in.www1.artemis.domain.participation.Participation in project ArTEMiS by ls1intum.
the class ParticipationResource method createParticipation.
/**
* POST /participations : Create a new participation.
*
* @param participation the participation to create
* @return the ResponseEntity with status 201 (Created) and with body the new participation, or with status 400 (Bad Request) if the participation has already an ID
* @throws URISyntaxException if the Location URI syntax is incorrect
*/
@PostMapping("/participations")
@PreAuthorize("hasAnyRole('TA', 'INSTRUCTOR', 'ADMIN')")
@Timed
public ResponseEntity<Participation> createParticipation(@RequestBody Participation participation) throws URISyntaxException {
log.debug("REST request to save Participation : {}", participation);
Course course = participation.getExercise().getCourse();
if (!courseService.userHasTAPermissions(course)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
if (participation.getId() != null) {
throw new BadRequestAlertException("A new participation cannot already have an ID", ENTITY_NAME, "idexists");
}
Participation result = participationService.save(participation);
return ResponseEntity.created(new URI("/api/participations/" + result.getId())).headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString())).body(result);
}
use of de.tum.in.www1.artemis.domain.participation.Participation in project ArTEMiS by ls1intum.
the class ExerciseService method cleanup.
/**
* Delete build plans (except BASE) and optionally repositores of all exercise participations.
*
* @param id id of the exercise for which build plans in respective participations are deleted
*/
@Transactional
public java.io.File cleanup(Long id, boolean deleteRepositories) throws java.io.IOException {
Exercise exercise = findOneLoadParticipations(id);
log.info("Request to cleanup all participations for Exercise : {}", exercise.getTitle());
List<Repository> studentRepositories = new ArrayList<>();
Path finalZipFilePath = null;
if (Optional.ofNullable(exercise).isPresent() && exercise instanceof ProgrammingExercise) {
exercise.getParticipations().forEach(participation -> {
if (participation.getBuildPlanId() != null) {
// ignore participations without build plan id
try {
continuousIntegrationService.get().deleteBuildPlan(participation.getBuildPlanId());
} catch (BambooException ex) {
log.error(ex.getMessage());
if (ex.getCause() != null) {
log.error(ex.getCause().getMessage());
}
}
participation.setInitializationState(ParticipationState.INACTIVE);
participation.setBuildPlanId(null);
participationService.save(participation);
}
if (deleteRepositories == true && participation.getRepositoryUrl() != null) {
// ignore participations without repository URL
try {
// 1. clone the repository
Repository repo = gitService.get().getOrCheckoutRepository(participation);
// 2. collect the repo file
studentRepositories.add(repo);
} catch (GitAPIException | IOException ex) {
log.error("Archiving and deleting the repository " + participation.getRepositoryUrlAsUrl() + " did not work as expected", ex);
}
}
});
if (deleteRepositories == false) {
// in this case, we are done
return null;
}
if (studentRepositories.isEmpty()) {
log.info("No student repositories have been found.");
return null;
}
// from here on, deleteRepositories is true and does not need to be evaluated again
log.info("Create zip file for all repositories");
Files.createDirectories(Paths.get("zippedRepos"));
finalZipFilePath = Paths.get("zippedRepos", exercise.getCourse().getTitle() + " " + exercise.getTitle() + " Student Repositories.zip");
zipAllRepositories(studentRepositories, finalZipFilePath);
exercise.getParticipations().forEach(participation -> {
if (participation.getRepositoryUrl() != null) {
// ignore participations without repository URL
try {
// 3. delete the locally cloned repo again
gitService.get().deleteLocalRepository(participation);
} catch (IOException e) {
log.error("Archiving and deleting the repository " + participation.getRepositoryUrlAsUrl() + " did not work as expected", e);
}
// 4. finally delete the repository on the VC Server
versionControlService.get().deleteRepository(participation.getRepositoryUrlAsUrl());
participation.setRepositoryUrl(null);
participation.setInitializationState(ParticipationState.FINISHED);
participationService.save(participation);
}
});
scheduleForDeletion(finalZipFilePath, 300);
} else {
log.info("Exercise with id {} is not an instance of ProgrammingExercise. Ignoring the request to cleanup repositories and build plan", id);
return null;
}
return new java.io.File(finalZipFilePath.toString());
}
use of de.tum.in.www1.artemis.domain.participation.Participation in project ArTEMiS by ls1intum.
the class GitService method getOrCheckoutRepository.
/**
* Get the local repository for a given participation.
* If the local repo does not exist yet, it will be checked out.
*
* @param participation Participation the remote repository belongs to.
* @return
* @throws IOException
* @throws GitAPIException
*/
public Repository getOrCheckoutRepository(Participation participation) throws IOException, GitAPIException {
URL repoUrl = participation.getRepositoryUrlAsUrl();
Repository repository = getOrCheckoutRepository(repoUrl);
repository.setParticipation(participation);
return repository;
}
use of de.tum.in.www1.artemis.domain.participation.Participation in project ArTEMiS by ls1intum.
the class QuizStatisticService method recalculateStatistics.
/**
* 1. Go through all Results in the Participation and recalculate the score
* 2. Recalculate the statistics of the given quizExercise
*
* @param quizExercise the changed QuizExercise object which will be used to recalculate the existing Results and Statistics
*/
public void recalculateStatistics(QuizExercise quizExercise) {
// reset all statistics
if (quizExercise.getQuizPointStatistic() != null) {
quizExercise.getQuizPointStatistic().resetStatistic();
} else {
var quizPointStatistic = new QuizPointStatistic();
quizExercise.setQuizPointStatistic(quizPointStatistic);
quizPointStatistic.setQuiz(quizExercise);
quizExercise.recalculatePointCounters();
}
for (QuizQuestion quizQuestion : quizExercise.getQuizQuestions()) {
if (quizQuestion.getQuizQuestionStatistic() != null) {
quizQuestion.getQuizQuestionStatistic().resetStatistic();
}
}
// add the Results in every participation of the given quizExercise to the statistics
for (Participation participation : studentParticipationRepository.findByExerciseId(quizExercise.getId())) {
Result latestRatedResult = null;
Result latestUnratedResult = null;
// update all Results of a participation
for (Result result : resultRepository.findAllByParticipationIdOrderByCompletionDateDesc(participation.getId())) {
// find the latest rated Result
if (Boolean.TRUE.equals(result.isRated()) && (latestRatedResult == null || latestRatedResult.getCompletionDate().isBefore(result.getCompletionDate()))) {
latestRatedResult = result;
}
// find latest unrated Result
if (Boolean.FALSE.equals(result.isRated()) && (latestUnratedResult == null || latestUnratedResult.getCompletionDate().isBefore(result.getCompletionDate()))) {
latestUnratedResult = result;
}
}
// update statistics with the latest rated und unrated Result
quizExercise.addResultToAllStatistics(latestRatedResult);
quizExercise.addResultToAllStatistics(latestUnratedResult);
}
// save changed Statistics
quizPointStatisticRepository.save(quizExercise.getQuizPointStatistic());
quizPointStatisticRepository.flush();
for (QuizQuestion quizQuestion : quizExercise.getQuizQuestions()) {
if (quizQuestion.getQuizQuestionStatistic() != null) {
quizQuestionStatisticRepository.save(quizQuestion.getQuizQuestionStatistic());
quizQuestionStatisticRepository.flush();
}
}
}
use of de.tum.in.www1.artemis.domain.participation.Participation in project ArTEMiS by ls1intum.
the class QuizSubmissionService method checkSubmissionForLiveModeOrThrow.
/**
* Check that the user is allowed to currently submit to the specified exercise and throws an exception if not
*/
private void checkSubmissionForLiveModeOrThrow(Long exerciseId, String userLogin, String logText, long start) throws QuizSubmissionException {
// check if submission is still allowed
QuizExercise quizExercise = quizScheduleService.getQuizExercise(exerciseId);
if (quizExercise == null) {
// Fallback solution
log.info("Quiz not in QuizScheduleService cache, fetching from DB");
quizExercise = quizExerciseRepository.findByIdElseThrow(exerciseId);
quizExercise.setQuizBatches(null);
}
log.debug("{}: Received quiz exercise for user {} in quiz {} in {} µs.", logText, userLogin, exerciseId, (System.nanoTime() - start) / 1000);
if (!quizExercise.isQuizStarted() || quizExercise.isQuizEnded()) {
throw new QuizSubmissionException("The quiz is not active");
}
var cachedSubmission = quizScheduleService.getQuizSubmission(exerciseId, userLogin);
if (cachedSubmission.isSubmitted()) {
// the old submission has not yet been processed, so don't allow a new one yet
throw new QuizSubmissionException("You have already submitted the quiz");
}
if (quizExercise.getQuizMode() == QuizMode.SYNCHRONIZED) {
// the batch exists if the quiz is active, otherwise a new inactive batch is returned
if (!quizBatchService.getOrCreateSynchronizedQuizBatch(quizExercise).isSubmissionAllowed()) {
throw new QuizSubmissionException("The quiz is not active");
}
// in synchronized mode we cache the participation after we processed the submission, so we can check there if the submission was already processed
var cachedParticipation = quizScheduleService.getParticipation(exerciseId, userLogin);
if (cachedParticipation != null && cachedParticipation.getResults().stream().anyMatch(r -> r.getSubmission().isSubmitted())) {
throw new QuizSubmissionException("You have already submitted the quiz");
}
} else {
// in the other modes the resubmission checks are done at join time and the student-batch association is removed when processing a submission
var batch = quizBatchService.getQuizBatchForStudentByLogin(quizExercise, userLogin);
// there is no way of distinguishing these two error cases without an extra db query
if (batch.isEmpty()) {
throw new QuizSubmissionException("You did not join or have already submitted the quiz");
}
if (!batch.get().isSubmissionAllowed()) {
throw new QuizSubmissionException("The quiz is not active");
}
}
// TODO: additional checks that may be beneficial
// for example it is possible for students that are not members of the course to submit the quiz
// but for performance reasons the checks may have to be done in the quiz submission service where no feedback for the students can be generated
}
Aggregations