Search in sources :

Example 16 with ExerciseGroup

use of de.tum.in.www1.artemis.domain.exam.ExerciseGroup in project ArTEMiS by ls1intum.

the class ExerciseGroupResource method createExerciseGroup.

/**
 * POST /courses/{courseId}/exams/{examId}/exerciseGroups : Create a new exercise group.
 *
 * @param courseId      the course to which the exercise group belongs to
 * @param examId        the exam to which the exercise group belongs to
 * @param exerciseGroup the exercise group to create
 * @return the ResponseEntity with status 201 (Created) and with the new exerciseGroup as body,
 *         or with status 400 (Bad Request) if the exerciseGroup has already an ID
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
@PostMapping("/courses/{courseId}/exams/{examId}/exerciseGroups")
@PreAuthorize("hasRole('EDITOR')")
public ResponseEntity<ExerciseGroup> createExerciseGroup(@PathVariable Long courseId, @PathVariable Long examId, @RequestBody ExerciseGroup exerciseGroup) throws URISyntaxException {
    log.debug("REST request to create an exercise group : {}", exerciseGroup);
    if (exerciseGroup.getId() != null) {
        throw new BadRequestAlertException("A new exerciseGroup cannot already have an ID", ENTITY_NAME, "idexists");
    }
    if (exerciseGroup.getExam() == null) {
        throw new ConflictException("The exercise group has to belong no an exam.", ENTITY_NAME, "missingExam");
    }
    if (!exerciseGroup.getExam().getId().equals(examId)) {
        throw new ConflictException("The exam connected to this group does not have the given exam id.", ENTITY_NAME, "wrongExamId");
    }
    examAccessService.checkCourseAndExamAccessForEditorElseThrow(courseId, examId);
    // Save the exerciseGroup as part of the exam to ensure that the order column is set correctly
    Exam examFromDB = examRepository.findByIdWithExerciseGroupsElseThrow(examId);
    examFromDB.addExerciseGroup(exerciseGroup);
    Exam savedExam = examRepository.save(examFromDB);
    ExerciseGroup savedExerciseGroup = savedExam.getExerciseGroups().get(savedExam.getExerciseGroups().size() - 1);
    return ResponseEntity.created(new URI("/api/courses/" + courseId + "/exams/" + examId + "/exerciseGroups/" + savedExerciseGroup.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, savedExerciseGroup.getTitle())).body(savedExerciseGroup);
}
Also used : BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) ConflictException(de.tum.in.www1.artemis.web.rest.errors.ConflictException) ExerciseGroup(de.tum.in.www1.artemis.domain.exam.ExerciseGroup) URI(java.net.URI) Exam(de.tum.in.www1.artemis.domain.exam.Exam) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 17 with ExerciseGroup

use of de.tum.in.www1.artemis.domain.exam.ExerciseGroup in project ArTEMiS by ls1intum.

the class ModelingExerciseResource method updateModelingExercise.

/**
 * PUT modeling-exercises : Updates an existing modelingExercise.
 *
 * @param modelingExercise the modelingExercise to update
 * @param notificationText the text shown to students
 * @return the ResponseEntity with status 200 (OK) and with body the updated modelingExercise, or with status 400 (Bad Request) if the modelingExercise is not valid, or with
 *         status 500 (Internal Server Error) if the modelingExercise couldn't be updated
 * @throws URISyntaxException if the Location URI syntax is incorrect
 */
@PutMapping("modeling-exercises")
@PreAuthorize("hasRole('EDITOR')")
public ResponseEntity<ModelingExercise> updateModelingExercise(@RequestBody ModelingExercise modelingExercise, @RequestParam(value = "notificationText", required = false) String notificationText) throws URISyntaxException {
    log.debug("REST request to update ModelingExercise : {}", modelingExercise);
    if (modelingExercise.getId() == null) {
        return createModelingExercise(modelingExercise);
    }
    // validates general settings: points, dates
    modelingExercise.validateGeneralSettings();
    // Valid exercises have set either a course or an exerciseGroup
    modelingExercise.checkCourseAndExerciseGroupExclusivity(ENTITY_NAME);
    // Check that the user is authorized to update the exercise
    var user = userRepository.getUserWithGroupsAndAuthorities();
    // Important: use the original exercise for permission check
    final ModelingExercise modelingExerciseBeforeUpdate = modelingExerciseRepository.findByIdElseThrow(modelingExercise.getId());
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, modelingExerciseBeforeUpdate, user);
    // Forbid changing the course the exercise belongs to.
    if (!Objects.equals(modelingExerciseBeforeUpdate.getCourseViaExerciseGroupOrCourseMember().getId(), modelingExercise.getCourseViaExerciseGroupOrCourseMember().getId())) {
        throw new ConflictException("Exercise course id does not match the stored course id", ENTITY_NAME, "cannotChangeCourseId");
    }
    // Forbid conversion between normal course exercise and exam exercise
    exerciseService.checkForConversionBetweenExamAndCourseExercise(modelingExercise, modelingExerciseBeforeUpdate, ENTITY_NAME);
    ModelingExercise updatedModelingExercise = modelingExerciseRepository.save(modelingExercise);
    exerciseService.logUpdate(modelingExercise, modelingExercise.getCourseViaExerciseGroupOrCourseMember(), user);
    exerciseService.updatePointsInRelatedParticipantScores(modelingExerciseBeforeUpdate, updatedModelingExercise);
    participationRepository.removeIndividualDueDatesIfBeforeDueDate(updatedModelingExercise, modelingExerciseBeforeUpdate.getDueDate());
    modelingExerciseService.scheduleOperations(updatedModelingExercise.getId());
    exerciseService.checkExampleSubmissions(updatedModelingExercise);
    groupNotificationService.checkAndCreateAppropriateNotificationsWhenUpdatingExercise(modelingExerciseBeforeUpdate, updatedModelingExercise, notificationText, instanceMessageSendService);
    return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME, modelingExercise.getId().toString())).body(updatedModelingExercise);
}
Also used : ConflictException(de.tum.in.www1.artemis.web.rest.errors.ConflictException) ModelingExercise(de.tum.in.www1.artemis.domain.modeling.ModelingExercise) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 18 with ExerciseGroup

use of de.tum.in.www1.artemis.domain.exam.ExerciseGroup in project ArTEMiS by ls1intum.

the class ProgrammingExerciseExportImportResource method importProgrammingExercise.

/**
 * POST /programming-exercises/import: Imports an existing programming exercise into an existing course
 * <p>
 * This will import the whole exercise, including all base build plans (template, solution) and repositories
 * (template, solution, test). Referenced entities, s.a. the test cases or the hints will get cloned and assigned
 * a new id. For a concrete list of what gets copied and what not have a look
 * at {@link ProgrammingExerciseImportService#importProgrammingExerciseBasis(ProgrammingExercise, ProgrammingExercise)}
 *
 * @param sourceExerciseId   The ID of the original exercise which should get imported
 * @param newExercise        The new exercise containing values that should get overwritten in the imported exercise, s.a. the title or difficulty
 * @param recreateBuildPlans Option determining whether the build plans should be copied or re-created from scratch
 * @param updateTemplate     Option determining whether the template files should be updated with the most recent template version
 * @return The imported exercise (200), a not found error (404) if the template does not exist, or a forbidden error
 * (403) if the user is not at least an instructor in the target course.
 * @see ProgrammingExerciseImportService#importProgrammingExerciseBasis(ProgrammingExercise, ProgrammingExercise)
 * @see ProgrammingExerciseImportService#importBuildPlans(ProgrammingExercise, ProgrammingExercise)
 * @see ProgrammingExerciseImportService#importRepositories(ProgrammingExercise, ProgrammingExercise)
 */
@PostMapping(IMPORT)
@PreAuthorize("hasRole('EDITOR')")
@FeatureToggle(Feature.ProgrammingExercises)
public ResponseEntity<ProgrammingExercise> importProgrammingExercise(@PathVariable long sourceExerciseId, @RequestBody ProgrammingExercise newExercise, @RequestParam(defaultValue = "false") boolean recreateBuildPlans, @RequestParam(defaultValue = "false") boolean updateTemplate) {
    if (sourceExerciseId < 0) {
        throw new BadRequestAlertException("Invalid source id when importing programming exercises", ENTITY_NAME, "invalidSourceExerciseId");
    }
    // Valid exercises have set either a course or an exerciseGroup
    newExercise.checkCourseAndExerciseGroupExclusivity(ENTITY_NAME);
    log.debug("REST request to import programming exercise {} into course {}", sourceExerciseId, newExercise.getCourseViaExerciseGroupOrCourseMember().getId());
    newExercise.validateGeneralSettings();
    newExercise.validateProgrammingSettings();
    validateStaticCodeAnalysisSettings(newExercise);
    final var user = userRepository.getUserWithGroupsAndAuthorities();
    Course course = courseService.retrieveCourseOverExerciseGroupOrCourseId(newExercise);
    authCheckService.checkHasAtLeastRoleInCourseElseThrow(Role.EDITOR, course, user);
    // Validate course settings
    programmingExerciseRepository.validateCourseSettings(newExercise, course);
    final var originalProgrammingExercise = programmingExerciseRepository.findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndTasksWithTestCases(sourceExerciseId).orElseThrow(() -> new EntityNotFoundException("ProgrammingExercise", sourceExerciseId));
    // The static code analysis flag can only change, if the build plans are recreated and the template is upgraded
    if (newExercise.isStaticCodeAnalysisEnabled() != originalProgrammingExercise.isStaticCodeAnalysisEnabled() && !(recreateBuildPlans && updateTemplate)) {
        throw new BadRequestAlertException("Static code analysis can only change, if the recreation of build plans and update of template files is activated", ENTITY_NAME, "staticCodeAnalysisCannotChange");
    }
    // If the new exercise has a submission policy, it must be validated.
    if (newExercise.getSubmissionPolicy() != null) {
        submissionPolicyService.validateSubmissionPolicy(newExercise.getSubmissionPolicy());
    }
    // Check if the user has the rights to access the original programming exercise
    Course originalCourse = courseService.retrieveCourseOverExerciseGroupOrCourseId(originalProgrammingExercise);
    authCheckService.checkHasAtLeastRoleInCourseElseThrow(Role.EDITOR, originalCourse, user);
    newExercise.generateAndSetProjectKey();
    programmingExerciseService.checkIfProjectExists(newExercise);
    final var importedProgrammingExercise = programmingExerciseImportService.importProgrammingExerciseBasis(originalProgrammingExercise, newExercise);
    programmingExerciseImportService.importRepositories(originalProgrammingExercise, importedProgrammingExercise);
    // Update the template files
    if (updateTemplate) {
        TemplateUpgradeService upgradeService = templateUpgradePolicy.getUpgradeService(importedProgrammingExercise.getProgrammingLanguage());
        upgradeService.upgradeTemplate(importedProgrammingExercise);
    }
    HttpHeaders responseHeaders;
    // Copy or recreate the build plans
    try {
        if (recreateBuildPlans) {
            // Create completely new build plans for the exercise
            programmingExerciseService.setupBuildPlansForNewExercise(importedProgrammingExercise);
        } else {
            // We have removed the automatic build trigger from test to base for new programming exercises.
            // We also remove this build trigger in the case of an import as the source exercise might still have this trigger.
            // The importBuildPlans method includes this process
            programmingExerciseImportService.importBuildPlans(originalProgrammingExercise, importedProgrammingExercise);
        }
        responseHeaders = HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, importedProgrammingExercise.getTitle());
    } catch (Exception e) {
        responseHeaders = HeaderUtil.createFailureAlert(applicationName, true, ENTITY_NAME, "importExerciseTriggerPlanFail", "Unable to trigger imported build plans");
    }
    programmingExerciseService.scheduleOperations(importedProgrammingExercise.getId());
    // Remove unnecessary fields
    importedProgrammingExercise.setTestCases(null);
    importedProgrammingExercise.setStaticCodeAnalysisCategories(null);
    importedProgrammingExercise.setTemplateParticipation(null);
    importedProgrammingExercise.setSolutionParticipation(null);
    importedProgrammingExercise.setExerciseHints(null);
    importedProgrammingExercise.setTasks(null);
    return ResponseEntity.ok().headers(responseHeaders).body(importedProgrammingExercise);
}
Also used : BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) HttpHeaders(org.springframework.http.HttpHeaders) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) Course(de.tum.in.www1.artemis.domain.Course) BadRequestAlertException(de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException) IOException(java.io.IOException) EntityNotFoundException(de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException) FeatureToggle(de.tum.in.www1.artemis.service.feature.FeatureToggle) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 19 with ExerciseGroup

use of de.tum.in.www1.artemis.domain.exam.ExerciseGroup in project ArTEMiS by ls1intum.

the class ModelingExerciseIntegrationTest method testUpdateModelingExerciseForExam_invalidExercise_dates.

@ParameterizedTest(name = "{displayName} [{index}] {argumentsWithNames}")
@ArgumentsSource(InvalidExamExerciseDatesArgumentProvider.class)
@WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
public void testUpdateModelingExerciseForExam_invalidExercise_dates(InvalidExamExerciseDateConfiguration invalidDates) throws Exception {
    ExerciseGroup exerciseGroup = database.addExerciseGroupWithExamAndCourse(true);
    ModelingExercise modelingExercise = ModelFactory.generateModelingExerciseForExam(DiagramType.ClassDiagram, exerciseGroup);
    modelingExerciseRepository.save(modelingExercise);
    request.postWithResponseBody("/api/modeling-exercises/", invalidDates.applyTo(modelingExercise), ProgrammingExercise.class, HttpStatus.BAD_REQUEST);
}
Also used : ModelingExercise(de.tum.in.www1.artemis.domain.modeling.ModelingExercise) ExerciseGroup(de.tum.in.www1.artemis.domain.exam.ExerciseGroup) WithMockUser(org.springframework.security.test.context.support.WithMockUser) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) ArgumentsSource(org.junit.jupiter.params.provider.ArgumentsSource)

Example 20 with ExerciseGroup

use of de.tum.in.www1.artemis.domain.exam.ExerciseGroup in project ArTEMiS by ls1intum.

the class ModelingExerciseIntegrationTest method createModelingExerciseForExam.

@Test
@WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
public void createModelingExerciseForExam() throws Exception {
    ExerciseGroup exerciseGroup = database.addExerciseGroupWithExamAndCourse(true);
    ModelingExercise modelingExercise = ModelFactory.generateModelingExerciseForExam(DiagramType.ClassDiagram, exerciseGroup);
    String title = "New Exam Modeling Exercise";
    DifficultyLevel difficulty = DifficultyLevel.HARD;
    modelingExercise.setTitle(title);
    modelingExercise.setDifficulty(difficulty);
    ModelingExercise newModelingExercise = request.postWithResponseBody("/api/modeling-exercises/", modelingExercise, ModelingExercise.class, HttpStatus.CREATED);
    assertThat(newModelingExercise.getTitle()).as("modeling exercise title was correctly set").isEqualTo(title);
    assertThat(newModelingExercise.getDifficulty()).as("modeling exercise difficulty was correctly set").isEqualTo(difficulty);
    assertThat(newModelingExercise.isCourseExercise()).as("course was not set for exam exercise").isFalse();
    assertThat(newModelingExercise.getExerciseGroup()).as("exerciseGroup was set for exam exercise").isNotNull();
    assertThat(newModelingExercise.getExerciseGroup().getId()).as("exerciseGroupId was set correctly").isEqualTo(exerciseGroup.getId());
}
Also used : ModelingExercise(de.tum.in.www1.artemis.domain.modeling.ModelingExercise) ExerciseGroup(de.tum.in.www1.artemis.domain.exam.ExerciseGroup) WithMockUser(org.springframework.security.test.context.support.WithMockUser) Test(org.junit.jupiter.api.Test) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Aggregations

ExerciseGroup (de.tum.in.www1.artemis.domain.exam.ExerciseGroup)126 WithMockUser (org.springframework.security.test.context.support.WithMockUser)76 Test (org.junit.jupiter.api.Test)70 Exam (de.tum.in.www1.artemis.domain.exam.Exam)64 StudentExam (de.tum.in.www1.artemis.domain.exam.StudentExam)46 ModelingExercise (de.tum.in.www1.artemis.domain.modeling.ModelingExercise)46 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)24 QuizExercise (de.tum.in.www1.artemis.domain.quiz.QuizExercise)22 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)22 AbstractSpringIntegrationBambooBitbucketJiraTest (de.tum.in.www1.artemis.AbstractSpringIntegrationBambooBitbucketJiraTest)20 BadRequestAlertException (de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException)20 StudentParticipation (de.tum.in.www1.artemis.domain.participation.StudentParticipation)18 EntityNotFoundException (de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException)14 TextExercise (de.tum.in.www1.artemis.domain.TextExercise)12 ZonedDateTime (java.time.ZonedDateTime)12 de.tum.in.www1.artemis.domain (de.tum.in.www1.artemis.domain)10 de.tum.in.www1.artemis.repository (de.tum.in.www1.artemis.repository)10 Collectors (java.util.stream.Collectors)10 ModelingSubmission (de.tum.in.www1.artemis.domain.modeling.ModelingSubmission)8 Participation (de.tum.in.www1.artemis.domain.participation.Participation)8