Search in sources :

Example 1 with FeatureToggle

use of de.tum.in.www1.artemis.service.feature.FeatureToggle 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 2 with FeatureToggle

use of de.tum.in.www1.artemis.service.feature.FeatureToggle in project ArTEMiS by ls1intum.

the class ProgrammingExerciseExportImportResource method exportSolutionRepository.

/**
 * GET /programming-exercises/:exerciseId/export-solution-repository : sends a solution repository as a zip file without .git directory.
 * @param exerciseId The id of the programming exercise
 * @return ResponseEntity with status
 * @throws IOException if something during the zip process went wrong
 */
@GetMapping(EXPORT_SOLUTION_REPOSITORY)
@PreAuthorize("hasRole('USER')")
@FeatureToggle(Feature.ProgrammingExercises)
public ResponseEntity<Resource> exportSolutionRepository(@PathVariable long exerciseId) throws IOException {
    var programmingExercise = programmingExerciseRepository.findByIdElseThrow(exerciseId);
    Role atLeastRole = programmingExercise.isExampleSolutionPublished() ? Role.STUDENT : Role.TEACHING_ASSISTANT;
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(atLeastRole, programmingExercise, null);
    long start = System.nanoTime();
    Optional<File> zipFile = programmingExerciseExportService.exportSolutionRepositoryForExercise(programmingExercise.getId(), new ArrayList<>());
    return returnZipFileForRepositoryExport(zipFile, RepositoryType.SOLUTION.getName(), programmingExercise, start);
}
Also used : Role(de.tum.in.www1.artemis.security.Role) File(java.io.File) FeatureToggle(de.tum.in.www1.artemis.service.feature.FeatureToggle) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 3 with FeatureToggle

use of de.tum.in.www1.artemis.service.feature.FeatureToggle in project ArTEMiS by ls1intum.

the class ProgrammingExerciseExportImportResource method exportInstructorExercise.

/**
 * GET /programming-exercises/:exerciseId/export-instructor-exercise
 * @param exerciseId The id of the programming exercise
 * @return ResponseEntity with status
 * @throws IOException if something during the zip process went wrong
 */
@GetMapping(EXPORT_INSTRUCTOR_EXERCISE)
@PreAuthorize("hasRole('INSTRUCTOR')")
@FeatureToggle(Feature.ProgrammingExercises)
public ResponseEntity<Resource> exportInstructorExercise(@PathVariable long exerciseId) throws IOException {
    var programmingExercise = programmingExerciseRepository.findByIdElseThrow(exerciseId);
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.INSTRUCTOR, programmingExercise, null);
    long start = System.nanoTime();
    var path = programmingExerciseExportService.exportProgrammingExerciseInstructorMaterial(programmingExercise, new ArrayList<>());
    if (path == null) {
        return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, ENTITY_NAME, "internalServerError", "There was an error on the server and the zip file could not be created.")).body(null);
    }
    var finalZipFile = path.toFile();
    InputStreamResource resource = new InputStreamResource(new FileInputStream(finalZipFile));
    log.info("Export of the programming exercise {} with title '{}' was successful in {}.", programmingExercise.getId(), programmingExercise.getTitle(), formatDurationFrom(start));
    return ResponseEntity.ok().contentLength(finalZipFile.length()).contentType(MediaType.APPLICATION_OCTET_STREAM).header("filename", finalZipFile.getName()).body(resource);
}
Also used : FileInputStream(java.io.FileInputStream) InputStreamResource(org.springframework.core.io.InputStreamResource) FeatureToggle(de.tum.in.www1.artemis.service.feature.FeatureToggle) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 4 with FeatureToggle

use of de.tum.in.www1.artemis.service.feature.FeatureToggle in project ArTEMiS by ls1intum.

the class ProgrammingExercisePlagiarismResource method checkPlagiarism.

/**
 * GET /programming-exercises/{exerciseId}/check-plagiarism : Start the automated plagiarism detection for the given exercise and return its result.
 *
 * @param exerciseId          The ID of the programming exercise for which the plagiarism check should be executed
 * @param similarityThreshold ignore comparisons whose similarity is below this threshold (%)
 * @param minimumScore        consider only submissions whose score is greater or equal to this value
 * @return the ResponseEntity with status 200 (OK) and the list of at most 500 pair-wise submissions with a similarity above the given threshold (e.g. 50%).
 * @throws ExitException is thrown if JPlag exits unexpectedly
 * @throws IOException   is thrown for file handling errors
 */
@GetMapping(CHECK_PLAGIARISM)
@PreAuthorize("hasRole('EDITOR')")
@FeatureToggle({ Feature.ProgrammingExercises, Feature.PlagiarismChecks })
public ResponseEntity<TextPlagiarismResult> checkPlagiarism(@PathVariable long exerciseId, @RequestParam float similarityThreshold, @RequestParam int minimumScore) throws ExitException, IOException {
    ProgrammingExercise programmingExercise = programmingExerciseRepository.findByIdElseThrow(exerciseId);
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, programmingExercise, null);
    ProgrammingLanguage language = programmingExercise.getProgrammingLanguage();
    ProgrammingLanguageFeature programmingLanguageFeature = programmingLanguageFeatureService.get().getProgrammingLanguageFeatures(language);
    if (!programmingLanguageFeature.isPlagiarismCheckSupported()) {
        return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, ENTITY_NAME, "programmingLanguageNotSupported", "Artemis does not support plagiarism checks for the programming language " + language)).body(null);
    }
    long start = System.nanoTime();
    log.info("Start programmingPlagiarismDetectionService.checkPlagiarism for exercise {}", exerciseId);
    TextPlagiarismResult result = programmingPlagiarismDetectionService.checkPlagiarism(exerciseId, similarityThreshold, minimumScore);
    log.info("Finished programmingExerciseExportService.checkPlagiarism call for {} comparisons in {}", result.getComparisons().size(), TimeLogUtil.formatDurationFrom(start));
    for (var comparison : result.getComparisons()) {
        comparison.setPlagiarismResult(null);
        comparison.getSubmissionA().setPlagiarismComparison(null);
        comparison.getSubmissionB().setPlagiarismComparison(null);
    }
    return ResponseEntity.ok(result);
}
Also used : TextPlagiarismResult(de.tum.in.www1.artemis.domain.plagiarism.text.TextPlagiarismResult) ProgrammingExercise(de.tum.in.www1.artemis.domain.ProgrammingExercise) ProgrammingLanguage(de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage) ProgrammingLanguageFeature(de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature) FeatureToggle(de.tum.in.www1.artemis.service.feature.FeatureToggle) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Example 5 with FeatureToggle

use of de.tum.in.www1.artemis.service.feature.FeatureToggle in project ArTEMiS by ls1intum.

the class ProgrammingExercisePlagiarismResource method getPlagiarismResult.

/**
 * GET /programming-exercises/{exerciseId}/plagiarism-result : Return the latest plagiarism result or null, if no plagiarism was detected for this exercise yet.
 *
 * @param exerciseId ID of the programming exercise for which the plagiarism result should be returned
 * @return The ResponseEntity with status 200 (Ok) or with status 400 (Bad Request) if the parameters are invalid
 */
@GetMapping(PLAGIARISM_RESULT)
@PreAuthorize("hasRole('EDITOR')")
@FeatureToggle(Feature.ProgrammingExercises)
public ResponseEntity<TextPlagiarismResult> getPlagiarismResult(@PathVariable long exerciseId) {
    log.debug("REST request to get the latest plagiarism result for the programming exercise with id: {}", exerciseId);
    ProgrammingExercise programmingExercise = programmingExerciseRepository.findByIdElseThrow(exerciseId);
    authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, programmingExercise, null);
    var plagiarismResult = plagiarismResultRepository.findFirstByExerciseIdOrderByLastModifiedDateDescOrNull(programmingExercise.getId());
    if (plagiarismResult != null) {
        for (var comparison : plagiarismResult.getComparisons()) {
            comparison.setPlagiarismResult(null);
            comparison.getSubmissionA().setPlagiarismComparison(null);
            comparison.getSubmissionB().setPlagiarismComparison(null);
        }
    }
    return ResponseEntity.ok((TextPlagiarismResult) plagiarismResult);
}
Also used : ProgrammingExercise(de.tum.in.www1.artemis.domain.ProgrammingExercise) FeatureToggle(de.tum.in.www1.artemis.service.feature.FeatureToggle) PreAuthorize(org.springframework.security.access.prepost.PreAuthorize)

Aggregations

FeatureToggle (de.tum.in.www1.artemis.service.feature.FeatureToggle)24 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)24 ProgrammingExercise (de.tum.in.www1.artemis.domain.ProgrammingExercise)8 File (java.io.File)6 IOException (java.io.IOException)6 URISyntaxException (java.net.URISyntaxException)6 Course (de.tum.in.www1.artemis.domain.Course)4 ContinuousIntegrationException (de.tum.in.www1.artemis.exception.ContinuousIntegrationException)4 ProgrammingLanguageFeature (de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature)4 BadRequestAlertException (de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException)4 EntityNotFoundException (de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException)4 FileInputStream (java.io.FileInputStream)4 URI (java.net.URI)4 GitAPIException (org.eclipse.jgit.api.errors.GitAPIException)4 InputStreamResource (org.springframework.core.io.InputStreamResource)4 HttpHeaders (org.springframework.http.HttpHeaders)4 AuxiliaryRepository (de.tum.in.www1.artemis.domain.AuxiliaryRepository)2 User (de.tum.in.www1.artemis.domain.User)2 ProgrammingLanguage (de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage)2 ProgrammingExerciseStudentParticipation (de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation)2