From f6b45e0fc2203f883d818bc1dd82d511205b64fa Mon Sep 17 00:00:00 2001 From: Jan Thurner <107639007+Jan-Thurner@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:54:18 +0200 Subject: [PATCH 01/10] Development: Analyze REST calls and endpoints (#8771) --- .../analysis-of-endpoint-connections.yml | 79 ++++--- settings.gradle | 1 + .../build.gradle | 24 +- ...{eslint.conjig.json => eslint.config.json} | 7 +- .../AnalysisOfEndpointConnections.java | 83 ------- .../endpointanalysis/EndpointAnalysis.java | 6 + .../endpointanalysis/EndpointAnalyzer.java | 144 ++++++++++++ .../EndpointClassInformation.java | 6 + .../endpointanalysis/EndpointInformation.java | 36 +++ .../cit/endpointanalysis/EndpointParser.java | 217 ++++++++++++++++++ .../endpointanalysis/RestCallAnalysis.java | 6 + .../endpointanalysis/RestCallAnalyzer.java | 144 ++++++++++++ .../RestCallFileInformation.java | 4 + .../endpointanalysis/RestCallInformation.java | 18 ++ .../RestCallWithMatchingEndpoint.java | 4 + .../cit/endpointanalysis/UsedEndpoints.java | 6 + .../AnalysisOfEndpointConnectionsClient.ts | 53 ++++- .../src/main/typeScript/Postprocessor.ts | 22 +- .../src/main/typeScript/Preprocessor.ts | 26 +-- 19 files changed, 729 insertions(+), 157 deletions(-) rename supporting_scripts/analysis-of-endpoint-connections/{eslint.conjig.json => eslint.config.json} (72%) delete mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java diff --git a/.github/workflows/analysis-of-endpoint-connections.yml b/.github/workflows/analysis-of-endpoint-connections.yml index 25849bddd012..2116605bea0a 100644 --- a/.github/workflows/analysis-of-endpoint-connections.yml +++ b/.github/workflows/analysis-of-endpoint-connections.yml @@ -1,12 +1,8 @@ +name: Analysis of Endpoint Connections + on: workflow_dispatch: - pull_request: - types: - - opened - - synchronize - paths: - - 'src/main/java/**' - - 'src/main/webapp/**' + push: # Keep in sync with build.yml and test.yml and codeql-analysis.yml env: @@ -15,7 +11,7 @@ env: java: 21 jobs: - analysis-of-endpoint-connections: + Parse-rest-calls-and-endpoints: timeout-minutes: 10 runs-on: ubuntu-latest steps: @@ -24,39 +20,70 @@ jobs: with: fetch-depth: 0 - - name: Get list of modified files - run: | - git diff --name-only origin/${{ github.event.pull_request.base.ref }} HEAD > modified_files.txt + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '${{ env.java }}' + distribution: 'temurin' + cache: 'gradle' - # Analyze the client sided REST-API calls - - name: Set up Node.js + - name: Set up node.js uses: actions/setup-node@v4 with: node-version: '${{ env.node }}' - - name: Install and compile TypeScript + - name: Parse client sided REST-API calls run: | - cd supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/ npm install - tsc -p tsconfig.analysisOfEndpointConnections.json - - - name: Run analysis-of-endpoint-connections-client - run: | + tsc -p supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/tsconfig.analysisOfEndpointConnections.json node supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.js - - name: Upload JSON file + - name: Parse server sided Endpoints + run: ./gradlew :supporting_scripts:analysis-of-endpoint-connections:runEndpointParser + + - name: Upload parsing results uses: actions/upload-artifact@v4 with: - name: rest-calls-json - path: supporting_scripts/analysis-of-endpoint-connections/restCalls.json + name: REST API Parsing Results + path: | + supporting_scripts/analysis-of-endpoint-connections/endpoints.json + supporting_scripts/analysis-of-endpoint-connections/restCalls.json + + Analysis-of-endpoint-connections: + needs: Parse-rest-calls-and-endpoints + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 - # Analyze the server sided endpoints - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '${{ env.java }}' + cache: 'gradle' - - name: Run analysis-of-endpoint-connections - run: | - ./gradlew :supporting_scripts:analysis-of-endpoint-connections:run --args="$(cat modified_files.txt)" + - name: Download JSON files + uses: actions/download-artifact@v4 + with: + name: REST API Parsing Results + path: supporting_scripts/analysis-of-endpoint-connections/ + + - name: Analyze endpoints + run: + ./gradlew :supporting_scripts:analysis-of-endpoint-connections:runEndpointAnalysis + + - name: Analyze rest calls + run: + ./gradlew :supporting_scripts:analysis-of-endpoint-connections:runRestCallAnalysis + + - name: Upload analysis results + uses: actions/upload-artifact@v4 + with: + name: Endpoint and REST Call Analysis Results + path: | + supporting_scripts/analysis-of-endpoint-connections/endpointAnalysisResult.json + supporting_scripts/analysis-of-endpoint-connections/restCallAnalysisResult.json diff --git a/settings.gradle b/settings.gradle index b9f9d365979c..c99752089fcd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -14,6 +14,7 @@ pluginManagement { rootProject.name = 'Artemis' +// needed for rest call and endpoint analysis include 'supporting_scripts:analysis-of-endpoint-connections' // needed for programming exercise templates diff --git a/supporting_scripts/analysis-of-endpoint-connections/build.gradle b/supporting_scripts/analysis-of-endpoint-connections/build.gradle index ef2fa37c2f5a..0e41c785d65c 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/build.gradle +++ b/supporting_scripts/analysis-of-endpoint-connections/build.gradle @@ -13,20 +13,26 @@ repositories { evaluationDependsOn(':') dependencies { - implementation rootProject.ext.qDoxVersionReusable + implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.26.0' + implementation 'com.github.javaparser:javaparser-core:3.26.0' + implementation 'com.github.javaparser:javaparser-core-serialization:3.26.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0' implementation rootProject.ext.springBootStarterWeb + implementation 'org.slf4j:slf4j-api:1.7.32' + implementation 'ch.qos.logback:logback-classic:1.2.6' } -test { - useJUnitPlatform() +task runEndpointParser(type: JavaExec) { + classpath = sourceSets.main.runtimeClasspath + mainClass = 'de.tum.cit.endpointanalysis.EndpointParser' } -application { - mainClassName = 'de.tum.cit.endpointanalysis.AnalysisOfEndpointConnections' +task runEndpointAnalysis(type: JavaExec) { + classpath = sourceSets.main.runtimeClasspath + mainClass = 'de.tum.cit.endpointanalysis.EndpointAnalyzer' } -run { - if (project.hasProperty('appArgs')) { - args = project.appArgs.split(' ') - } +task runRestCallAnalysis(type: JavaExec) { + classpath = sourceSets.main.runtimeClasspath + mainClass = 'de.tum.cit.endpointanalysis.RestCallAnalyzer' } diff --git a/supporting_scripts/analysis-of-endpoint-connections/eslint.conjig.json b/supporting_scripts/analysis-of-endpoint-connections/eslint.config.json similarity index 72% rename from supporting_scripts/analysis-of-endpoint-connections/eslint.conjig.json rename to supporting_scripts/analysis-of-endpoint-connections/eslint.config.json index 0b47d7836035..393e1c0972cf 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/eslint.conjig.json +++ b/supporting_scripts/analysis-of-endpoint-connections/eslint.config.json @@ -10,10 +10,5 @@ "jsx": true } }, - "rules": {}, - "settings": { - "react": { - "version": "detect" - } - } + "rules": {} } diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java deleted file mode 100644 index b47b91d680d8..000000000000 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java +++ /dev/null @@ -1,83 +0,0 @@ -package de.tum.cit.endpointanalysis; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.thoughtworks.qdox.JavaProjectBuilder; -import com.thoughtworks.qdox.model.JavaAnnotation; -import com.thoughtworks.qdox.model.JavaClass; -import com.thoughtworks.qdox.model.JavaMethod; - -public class AnalysisOfEndpointConnections { - - /** - * This is the entry point of the analysis of server sided endpoints. - * - * @param args List of files that should be analyzed regarding endpoints. - */ - public static void main(String[] args) { - if (args.length == 0) { - System.out.println("No files to analyze."); - return; - } - String[] filePaths = args[0].split("\n"); - String[] serverFiles = Arrays.stream(filePaths).map(filePath -> Paths.get("..", "..", filePath).toString()) - .filter(filePath -> Files.exists(Paths.get(filePath)) && filePath.endsWith(".java")).toArray(String[]::new); - analyzeServerEndpoints(serverFiles); - } - - private static void analyzeServerEndpoints(String[] filePaths) { - final Set httpMethodClasses = Set.of(GetMapping.class.getName(), PostMapping.class.getName(), PutMapping.class.getName(), DeleteMapping.class.getName(), - PatchMapping.class.getName(), RequestMapping.class.getName()); - - JavaProjectBuilder builder = new JavaProjectBuilder(); - for (String filePath : filePaths) { - builder.addSourceTree(new File(filePath)); - } - - Collection classes = builder.getClasses(); - for (JavaClass javaClass : classes) { - Optional requestMappingOptional = javaClass.getAnnotations().stream() - .filter(annotation -> annotation.getType().getFullyQualifiedName().equals(RequestMapping.class.getName())).findFirst(); - - boolean hasEndpoint = javaClass.getMethods().stream().flatMap(method -> method.getAnnotations().stream()) - .anyMatch(annotation -> httpMethodClasses.contains(annotation.getType().getFullyQualifiedName())); - - if (hasEndpoint) { - System.out.println("=================================================="); - System.out.println("Class: " + javaClass.getFullyQualifiedName()); - requestMappingOptional.ifPresent(annotation -> System.out.println("Class Request Mapping: " + annotation.getProperty("value"))); - System.out.println("=================================================="); - } - - for (JavaMethod method : javaClass.getMethods()) { - for (JavaAnnotation annotation : method.getAnnotations()) { - if (httpMethodClasses.contains(annotation.getType().getFullyQualifiedName())) { - System.out.println("Endpoint: " + method.getName()); - System.out.println( - annotation.getType().getFullyQualifiedName().equals(RequestMapping.class.getName()) ? "RequestMapping·method: " + annotation.getProperty("method") - : "HTTP method annotation: " + annotation.getType().getName()); - System.out.println("Path: " + annotation.getProperty("value")); - System.out.println("Line: " + method.getLineNumber()); - List annotations = method.getAnnotations().stream().filter(a -> !a.equals(annotation)).map(a -> a.getType().getName()).toList(); - System.out.println("Other annotations: " + annotations); - System.out.println("---------------------------------------------------"); - } - } - } - } - } -} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java new file mode 100644 index 000000000000..4c38f7e826e8 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record EndpointAnalysis(List usedEndpoints, List unusedEndpoints) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java new file mode 100644 index 000000000000..250966bfd432 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java @@ -0,0 +1,144 @@ +package de.tum.cit.endpointanalysis; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class EndpointAnalyzer { + + private static String EndpointAnalysisResultPath = "endpointAnalysisResult.json"; + + private static final Logger logger = LoggerFactory.getLogger(EndpointAnalyzer.class); + + public static void main(String[] args) { + analyzeEndpoints(); + printEndpointAnalysisResult(); + } + + /** + * Analyzes server side endpoints and matches them with client side REST calls. + * + * This method reads endpoint and REST call information from JSON files, + * compares them to find matching REST calls for each endpoint, and writes + * the analysis result to a JSON file. Endpoints without matching REST calls + * are also recorded. + */ + private static void analyzeEndpoints() { + ObjectMapper mapper = new ObjectMapper(); + + try { + List endpointClasses = mapper.readValue(new File(EndpointParser.ENDPOINT_PARSING_RESULT_PATH), + new TypeReference>() { + }); + List restCallFiles = mapper.readValue(new File(EndpointParser.REST_CALL_PARSING_RESULT_PATH), + new TypeReference>() { + }); + + List endpointsAndMatchingRestCalls = new ArrayList<>(); + List unusedEndpoints = new ArrayList<>(); + + Map> restCallMap = new HashMap<>(); + + // Populate the map with rest calls + for (RestCallFileInformation restCallFile : restCallFiles) { + for (RestCallInformation restCall : restCallFile.restCalls()) { + String restCallURI = restCall.buildComparableRestCallUri(); + restCallMap.computeIfAbsent(restCallURI, uri -> new ArrayList<>()).add(restCall); + } + } + + for (EndpointClassInformation endpointClass : endpointClasses) { + for (EndpointInformation endpoint : endpointClass.endpoints()) { + + String endpointURI = endpoint.buildComparableEndpointUri(); + List matchingRestCalls = restCallMap.getOrDefault(endpointURI, new ArrayList<>()); + + // Check for wildcard endpoints if no exact match is found + checkForWildcardEndpoints(endpoint, matchingRestCalls, endpointURI, restCallMap); + + if (matchingRestCalls.isEmpty()) { + unusedEndpoints.add(endpoint); + } + else { + endpointsAndMatchingRestCalls.add(new UsedEndpoints(endpoint, matchingRestCalls, endpointClass.filePath())); + } + } + } + + EndpointAnalysis endpointAnalysis = new EndpointAnalysis(endpointsAndMatchingRestCalls, unusedEndpoints); + mapper.writeValue(new File(EndpointAnalysisResultPath), endpointAnalysis); + } + catch (IOException e) { + logger.error("Failed to analyze endpoints", e); + } + } + + /** + * Checks for wildcard endpoints and adds matching REST calls to the list. + * + * This method is used to find matching REST calls for endpoints that use wildcard URIs. + * If no exact match is found for an endpoint, it checks if the endpoint URI ends with a wildcard ('*'). + * It then iterates through the rest call map to find URIs that start with the same prefix as the endpoint URI + * (excluding the wildcard) and have the same HTTP method. If such URIs are found, they are added to the list of matching REST calls. + * + * @param endpoint The endpoint information to check for wildcard matches. + * @param matchingRestCalls The list of matching REST calls to be populated. + * @param endpointURI The URI of the endpoint being checked. + * @param restCallMap The map of rest call URIs to their corresponding information. + */ + private static void checkForWildcardEndpoints(EndpointInformation endpoint, List matchingRestCalls, String endpointURI, + Map> restCallMap) { + if (matchingRestCalls.isEmpty() && endpointURI.endsWith("*")) { + for (String uri : restCallMap.keySet()) { + if (uri.startsWith(endpoint.buildComparableEndpointUri().substring(0, endpoint.buildComparableEndpointUri().length() - 1)) + && endpoint.getHttpMethod().toLowerCase().equals(restCallMap.get(uri).get(0).method().toLowerCase())) { + matchingRestCalls.addAll(restCallMap.get(uri)); + } + } + } + } + + /** + * Prints the endpoint analysis result. + * + * This method reads the endpoint analysis result from a JSON file and prints + * the details of unused endpoints to the console. The details include the + * endpoint URI, HTTP method, file path, and line number. If no matching REST + * call is found for an endpoint, it prints a message indicating this. + */ + private static void printEndpointAnalysisResult() { + ObjectMapper mapper = new ObjectMapper(); + EndpointAnalysis endpointsAndMatchingRestCalls = null; + try { + endpointsAndMatchingRestCalls = mapper.readValue(new File(EndpointAnalysisResultPath), new TypeReference() { + }); + } + catch (IOException e) { + logger.error("Failed to deserialize endpoint analysis result", e); + return; + } + + endpointsAndMatchingRestCalls.unusedEndpoints().stream().forEach(endpoint -> { + logger.info("============================================="); + logger.info("Endpoint URI: {}", endpoint.buildCompleteEndpointURI()); + logger.info("HTTP method: {}", endpoint.httpMethodAnnotation()); + logger.info("File path: {}", endpoint.className()); + logger.info("Line: {}", endpoint.line()); + logger.info("============================================="); + logger.info("No matching REST call found for endpoint: {}", endpoint.buildCompleteEndpointURI()); + logger.info("---------------------------------------------"); + logger.info(""); + }); + + logger.info("Number of endpoints without matching REST calls: {}", endpointsAndMatchingRestCalls.unusedEndpoints().size()); + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java new file mode 100644 index 000000000000..062a3671b1bf --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record EndpointClassInformation(String filePath, String classRequestMapping, List endpoints) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java new file mode 100644 index 000000000000..19b32dc8881b --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java @@ -0,0 +1,36 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public record EndpointInformation(String requestMapping, String endpoint, String httpMethodAnnotation, String URI, String className, int line, List otherAnnotations) { + + public String buildCompleteEndpointURI() { + StringBuilder result = new StringBuilder(); + if (this.requestMapping != null && !this.requestMapping.isEmpty()) { + // Remove quotes from the requestMapping as they are used to define the String in the source code but are not part of the URI + result.append(this.requestMapping.replace("\"", "")); + } + // Remove quotes from the URI as they are used to define the String in the source code but are not part of the URI + result.append(this.URI.replace("\"", "")); + return result.toString(); + } + + String buildComparableEndpointUri() { + // Replace arguments with placeholder + return this.buildCompleteEndpointURI().replaceAll("\\{.*?\\}", ":param:"); + } + + @JsonIgnore + public String getHttpMethod() { + return switch (this.httpMethodAnnotation) { + case "GetMapping" -> "get"; + case "PostMapping" -> "post"; + case "PutMapping" -> "put"; + case "DeleteMapping" -> "delete"; + case "PatchMapping" -> "patch"; + default -> "No HTTP method annotation found"; + }; + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java new file mode 100644 index 000000000000..b0ab2cdb1f0b --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java @@ -0,0 +1,217 @@ +package de.tum.cit.endpointanalysis; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.expr.AnnotationExpr; +import com.github.javaparser.ast.expr.ArrayInitializerExpr; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.NormalAnnotationExpr; +import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr; + +public class EndpointParser { + + static final String ENDPOINT_PARSING_RESULT_PATH = "endpoints.json"; + + static final String REST_CALL_PARSING_RESULT_PATH = "restCalls.json"; + + private static final Logger logger = LoggerFactory.getLogger(EndpointParser.class); + + public static void main(String[] args) { + final Path absoluteDirectoryPath = Path.of("../../src/main/java").toAbsolutePath().normalize(); + + StaticJavaParser.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21); + + String[] filesToParse = {}; + try (Stream paths = Files.walk(absoluteDirectoryPath)) { + filesToParse = paths.filter(Files::isRegularFile).filter(path -> path.toString().endsWith(".java")).map(Path::toString).toArray(String[]::new); + } + catch (IOException e) { + logger.error("Error reading files from directory: {}", absoluteDirectoryPath, e); + } + + parseServerEndpoints(filesToParse); + } + + /** + * Parses server endpoints from the given file paths. + * + * This method reads Java files from the specified file paths, extracts endpoint + * information annotated with HTTP method annotations, and writes the parsed + * endpoint information to a JSON file. It also logs any files that failed to parse. + * + * @param filePaths an array of file paths to parse for endpoint information + */ + private static void parseServerEndpoints(String[] filePaths) { + List endpointClasses = new ArrayList<>(); + final Set httpMethodClasses = Set.of(GetMapping.class.getSimpleName(), PostMapping.class.getSimpleName(), PutMapping.class.getSimpleName(), + DeleteMapping.class.getSimpleName(), PatchMapping.class.getSimpleName(), RequestMapping.class.getSimpleName()); + List filesFailedToParse = new ArrayList<>(); + + for (String filePath : filePaths) { + CompilationUnit compilationUnit; + try { + compilationUnit = StaticJavaParser.parse(new File(filePath)); + } + catch (Exception e) { + filesFailedToParse.add(filePath); + continue; + } + + List classes = compilationUnit.findAll(ClassOrInterfaceDeclaration.class); + for (ClassOrInterfaceDeclaration javaClass : classes) { + List endpoints = new ArrayList<>(); + final String classRequestMappingString = extractClassRequestMapping(javaClass, httpMethodClasses); + + endpoints.addAll(extractAnnotationPathValues(javaClass, httpMethodClasses, classRequestMappingString)); + + if (!endpoints.isEmpty()) { + endpointClasses.add(new EndpointClassInformation(javaClass.getNameAsString(), classRequestMappingString, endpoints)); + } + } + } + + printFilesFailedToParse(filesFailedToParse); + + writeEndpointsToFile(endpointClasses); + } + + /** + * Extracts endpoint information from the methods of a given class declaration. + * + * This method iterates over the methods of the provided class and their annotations. + * If an annotation matches one of the specified HTTP method annotations, it extracts + * the path values from the annotation and creates EndpointInformation objects for each path. + * + * @param javaClass the class declaration to extract endpoint information from + * @param httpMethodClasses a set of HTTP method annotation class names + * @param classRequestMappingString the class-level request mapping string + * @return a list of EndpointInformation objects representing the extracted endpoint information + */ + private static List extractAnnotationPathValues(ClassOrInterfaceDeclaration javaClass, Set httpMethodClasses, String classRequestMappingString) { + return javaClass.getMethods().stream() + .flatMap(method -> method.getAnnotations().stream().filter(annotation -> httpMethodClasses.contains(annotation.getNameAsString())) + .flatMap(annotation -> extractPathsFromAnnotation(annotation).stream() + .map(path -> new EndpointInformation(classRequestMappingString, method.getNameAsString(), annotation.getNameAsString(), path, + javaClass.getNameAsString(), method.getBegin().get().line, method.getAnnotations().stream().map(AnnotationExpr::toString).toList())))) + .toList(); + } + + /** + * Extracts the paths from the given annotation. + * + * This method processes the provided annotation to extract path values. + * It handles both single-member and normal annotations, extracting the + * path values from the annotation's member values or pairs. + * + * @param annotation the annotation to extract paths from + * @return a list of extracted path values + */ + private static List extractPathsFromAnnotation(AnnotationExpr annotation) { + List paths = new ArrayList<>(); + if (annotation instanceof SingleMemberAnnotationExpr singleMemberAnnotationExpr) { + Expression memberValue = singleMemberAnnotationExpr.getMemberValue(); + if (memberValue instanceof ArrayInitializerExpr arrayInitializerExpr) { + paths.addAll(arrayInitializerExpr.getValues().stream().map(Expression::toString).collect(Collectors.toList())); + } + else { + paths.add(memberValue.toString()); + } + } + else if (annotation instanceof NormalAnnotationExpr normalAnnotationExpr) { + normalAnnotationExpr.getPairs().stream().filter(pair -> "value".equals(pair.getNameAsString())).forEach(pair -> paths.add(pair.getValue().toString())); + } + return paths; + } + + /** + * Extracts the class-level request mapping from a given class declaration. + * + * This method scans the annotations of the provided class to find a `RequestMapping` annotation. + * It then checks if the class contains any methods annotated with HTTP method annotations. + * If such methods are found, it extracts the value of the `RequestMapping` annotation. + * + * @param javaClass the class declaration to extract the request mapping from + * @param httpMethodClasses a set of HTTP method annotation class names + * @return the extracted request mapping value, or an empty string if no request mapping is found or the class has no HTTP method annotations + */ + private static String extractClassRequestMapping(ClassOrInterfaceDeclaration javaClass, Set httpMethodClasses) { + boolean hasEndpoint = javaClass.getMethods().stream().flatMap(method -> method.getAnnotations().stream()) + .anyMatch(annotation -> httpMethodClasses.contains(annotation.getNameAsString())); + + if (!hasEndpoint) { + return ""; + } + + String classRequestMapping = javaClass.getAnnotations().stream().filter(annotation -> annotation.getNameAsString().equals(RequestMapping.class.getSimpleName())).findFirst() + .map(annotation -> { + if (annotation instanceof SingleMemberAnnotationExpr singleMemberAnnotationExpr) { + return singleMemberAnnotationExpr.getMemberValue().toString(); + } + else if (annotation instanceof NormalAnnotationExpr normalAnnotationExpr) { + return normalAnnotationExpr.getPairs().stream().filter(pair -> "path".equals(pair.getNameAsString())).map(pair -> pair.getValue().toString()).findFirst() + .orElse(""); + } + return ""; + }).orElse(""); + + return classRequestMapping; + } + + /** + * Prints the list of files that failed to parse. + * + * This method checks if the provided list of file paths is not empty. + * If it is not empty, it prints a message indicating that some files failed to parse, + * followed by the paths of the files that failed. + * + * @param filesFailedToParse the list of file paths that failed to parse + */ + private static void printFilesFailedToParse(List filesFailedToParse) { + if (!filesFailedToParse.isEmpty()) { + logger.warn("Files failed to parse:", filesFailedToParse); + for (String file : filesFailedToParse) { + logger.warn(file); + } + } + } + + /** + * Writes the list of endpoint class information to a JSON file. + * + * This method uses the Jackson ObjectMapper to serialize the list of + * EndpointClassInformation objects and write them to a file specified + * by the EndpointParsingResultPath constant. + * + * @param endpointClasses the list of EndpointClassInformation objects to write to the file + */ + private static void writeEndpointsToFile(List endpointClasses) { + try { + new ObjectMapper().writeValue(new File(ENDPOINT_PARSING_RESULT_PATH), endpointClasses); + } + catch (IOException e) { + logger.error("Failed to write endpoint information to file", e); + } + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java new file mode 100644 index 000000000000..57b1d2dfc289 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record RestCallAnalysis(List restCallsWithMatchingEndpoints, List restCallsWithoutMatchingEndpoints) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java new file mode 100644 index 000000000000..aac71d6573bf --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java @@ -0,0 +1,144 @@ +package de.tum.cit.endpointanalysis; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RestCallAnalyzer { + + private static final String REST_CALL_ANALYSIS_RESULT_PATH = "restCallAnalysisResult.json"; + + private static final Logger logger = LoggerFactory.getLogger(RestCallAnalyzer.class); + + public static void main(String[] args) { + analyzeRestCalls(); + printRestCallAnalysisResult(); + } + + /** + * The RestCallAnalyzer analyzes the client REST Calls and focuses on them having a matching Endpoint on the server + * + * This method reads endpoint and REST call information from JSON files. + * It then matches the REST calls with the endpoints they are calling and + * writes the analysis result to a JSON file. + * REST calls without matching endpoints are also recorded. + */ + private static void analyzeRestCalls() { + ObjectMapper mapper = new ObjectMapper(); + + try { + List endpointClasses = mapper.readValue(new File(EndpointParser.ENDPOINT_PARSING_RESULT_PATH), + new TypeReference>() { + }); + List restCalls = mapper.readValue(new File(EndpointParser.REST_CALL_PARSING_RESULT_PATH), new TypeReference>() { + }); + + List restCallsWithMatchingEndpoint = new ArrayList<>(); + List restCallsWithoutMatchingEndpoint = new ArrayList<>(); + + Map> endpointMap = new HashMap<>(); + + // Populate the map with endpoints + for (EndpointClassInformation endpointClass : endpointClasses) { + for (EndpointInformation endpoint : endpointClass.endpoints()) { + String endpointURI = endpoint.buildComparableEndpointUri(); + endpointMap.computeIfAbsent(endpointURI, uri -> new ArrayList<>()).add(endpoint); + } + } + + for (RestCallFileInformation restCallFile : restCalls) { + for (RestCallInformation restCall : restCallFile.restCalls()) { + String restCallURI = restCall.buildComparableRestCallUri(); + List matchingEndpoints = endpointMap.getOrDefault(restCallURI, new ArrayList<>()); + + checkForWildcardMatches(restCall, matchingEndpoints, restCallURI, endpointMap); + + if (matchingEndpoints.isEmpty()) { + restCallsWithoutMatchingEndpoint.add(restCall); + } + else { + for (EndpointInformation endpoint : matchingEndpoints) { + restCallsWithMatchingEndpoint.add(new RestCallWithMatchingEndpoint(endpoint, restCall, restCall.fileName())); + } + } + } + } + + RestCallAnalysis restCallAnalysis = new RestCallAnalysis(restCallsWithMatchingEndpoint, restCallsWithoutMatchingEndpoint); + mapper.writeValue(new File(REST_CALL_ANALYSIS_RESULT_PATH), restCallAnalysis); + } + catch (IOException e) { + logger.error("Failed to analyze REST calls", e); + } + } + + /** + * Checks for wildcard matches and adds matching endpoints to the list. + * + * This method is used to find matching endpoints for REST calls that use wildcard URIs. + * If no exact match is found for a REST call, it checks if the REST call URI ends with a wildcard ('*'). + * It then iterates through the endpoint map to find URIs that start with the same prefix as the REST call URI + * (excluding the wildcard) and have the same HTTP method. If such URIs are found, they are added to the list of matching endpoints. + * + * @param restCall The REST call information to check for wildcard matches. + * @param matchingEndpoints The list of matching endpoints to be populated. + * @param restCallURI The URI of the REST call being checked. + * @param endpointMap The map of endpoint URIs to their corresponding information. + */ + private static void checkForWildcardMatches(RestCallInformation restCall, List matchingEndpoints, String restCallURI, + Map> endpointMap) { + if (matchingEndpoints.isEmpty() && restCallURI.endsWith("*")) { + for (String uri : endpointMap.keySet()) { + if (uri.startsWith(restCallURI.substring(0, restCallURI.length() - 1)) + && endpointMap.get(uri).get(0).getHttpMethod().toLowerCase().equals(restCall.method().toLowerCase())) { + matchingEndpoints.addAll(endpointMap.get(uri)); + } + } + } + } + + /** + * Prints the endpoint analysis result. + * + * This method reads the endpoint analysis result from a JSON file and prints + * the details of unused endpoints to the console. The details include the + * endpoint URI, HTTP method, file path, and line number. If no matching REST + * call is found for an endpoint, it prints a message indicating this. + */ + private static void printRestCallAnalysisResult() { + ObjectMapper mapper = new ObjectMapper(); + + RestCallAnalysis restCallsAndMatchingEndpoints = null; + + try { + restCallsAndMatchingEndpoints = mapper.readValue(new File(REST_CALL_ANALYSIS_RESULT_PATH), new TypeReference() { + }); + } + catch (IOException e) { + logger.error("Failed to deserialize rest call analysis results", e); + } + + restCallsAndMatchingEndpoints.restCallsWithoutMatchingEndpoints().stream().forEach(endpoint -> { + logger.info("============================================="); + logger.info("REST call URI: {}", endpoint.buildCompleteRestCallURI()); + logger.info("HTTP method: {}", endpoint.method()); + logger.info("File path: {}", endpoint.fileName()); + logger.info("Line: {}", endpoint.line()); + logger.info("============================================="); + logger.info("No matching endpoint found for REST call: {}", endpoint.buildCompleteRestCallURI()); + logger.info("---------------------------------------------"); + logger.info(""); + }); + + logger.info("Number of REST calls without matching endpoints: {}", restCallsAndMatchingEndpoints.restCallsWithoutMatchingEndpoints().size()); + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java new file mode 100644 index 000000000000..847ec03b1561 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java @@ -0,0 +1,4 @@ +package de.tum.cit.endpointanalysis; + +public record RestCallFileInformation(String fileName, RestCallInformation[] restCalls) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java new file mode 100644 index 000000000000..fb1e44f92f2a --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java @@ -0,0 +1,18 @@ +package de.tum.cit.endpointanalysis; + +public record RestCallInformation(String method, String url, int line, String fileName) { + + public String buildCompleteRestCallURI() { + return this.url.replace("`", ""); + } + + public String buildComparableRestCallUri() { + // Replace arguments with placeholder + String result = this.buildCompleteRestCallURI().replaceAll("\\$\\{.*?\\}", ":param:"); + + // Remove query parameters + result = result.split("\\?")[0]; + + return result; + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java new file mode 100644 index 000000000000..0b3ebed9d527 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java @@ -0,0 +1,4 @@ +package de.tum.cit.endpointanalysis; + +public record RestCallWithMatchingEndpoint(EndpointInformation matchingEndpoint, RestCallInformation restCallInformation, String filePath) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java new file mode 100644 index 000000000000..afdb8fa06846 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record UsedEndpoints(EndpointInformation endpointInformation, List matchingRestCalls, String filePath) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts index f774acfdc92b..ad4f19a9322e 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts @@ -1,8 +1,9 @@ -import { readdirSync } from 'node:fs'; +import { readdirSync, readFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; import { Preprocessor } from './Preprocessor'; import { Postprocessor } from './Postprocessor'; import { writeFileSync } from 'node:fs'; +import { parse, TSESTree } from '@typescript-eslint/typescript-estree'; /** * Recursively collects all TypeScript files in a directory. @@ -26,20 +27,58 @@ function collectTypeScriptFiles(dir: string, files: string[] = []) : string[] { return files; } +/** + * Parses a TypeScript file and returns its Abstract Syntax Tree (AST). + * + * @param filePath - The path to the TypeScript file to be parsed. + * @returns The TSESTree of the parsed TypeScript file. + */ +function parseTypeScriptFile(filePath: string): TSESTree.Program | null { + const code = readFileSync(filePath, 'utf8'); + try { + return parse(code, { + loc: true, + comment: true, + tokens: true, + ecmaVersion: 2020, + sourceType: 'module', + }); + } catch (error) { + console.error(`Failed to parse TypeScript file at ${filePath}:`, error); + console.error('Please make sure the file is valid TypeScript code.'); + return null; + } +} + const clientDirPath = resolve('src/main/webapp/app'); const tsFiles = collectTypeScriptFiles(clientDirPath); -// preprocess each file +// create and store Syntax Tree for each file +const astMap = new Map; tsFiles.forEach((filePath) => { - const preProcessor = new Preprocessor(filePath); - preProcessor.preprocessFile(); + const ast = parseTypeScriptFile(filePath); + if (ast) { + astMap.set(filePath, ast); + } +}); + +// preprocess each file +Array.from(astMap.keys()).forEach((filePath: string) => { + const ast = astMap.get(filePath); + if (ast) { + const preProcessor = new Preprocessor(ast); + preProcessor.preprocessFile(); + } }); // postprocess each file -tsFiles.forEach((filePath) => { - const postProcessor = new Postprocessor(filePath); - postProcessor.extractRestCalls(); +Array.from(astMap.keys()).forEach((filePath) => { + const ast = astMap.get(filePath); + if (ast) { + const postProcessor = new Postprocessor(filePath, ast); + postProcessor.extractRestCallsFromProgram(); + } }); try { diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts index b90d216a9796..18b54a5f0ac4 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts @@ -38,18 +38,18 @@ class ParsingResult { } export class Postprocessor { - static filesWithRestCalls: { filePath: string, restCalls: RestCall[] }[] = []; + static filesWithRestCalls: { fileName: string, restCalls: RestCall[] }[] = []; private readonly restCalls: RestCall[] = []; - private readonly filePath: string; + private readonly fileName: string; private readonly ast: TSESTree.Program; - constructor(filePath: string) { - this.filePath = filePath; - this.ast = Preprocessor.parseTypeScriptFile(Preprocessor.pathPrefix + filePath) - } - - extractRestCalls() { - this.extractRestCallsFromProgram(); + /** + * @param fileName - The name of the file being processed. + * @param ast - The abstract syntax tree (AST) of the processed file. + */ + constructor(fileName: string, ast: TSESTree.Program) { + this.fileName = fileName; + this.ast = ast; } extractRestCallsFromProgram() { @@ -61,7 +61,7 @@ export class Postprocessor { } }); if (this.restCalls.length > 0) { - Postprocessor.filesWithRestCalls.push( {filePath: this.filePath, restCalls: this.restCalls} ); + Postprocessor.filesWithRestCalls.push( {fileName: this.fileName, restCalls: this.restCalls} ); } } @@ -108,7 +108,7 @@ export class Postprocessor { urlEvaluationResult = this.evaluateUrl(node.arguments[0], methodDefinition, node, classBody); } - const fileName = this.filePath; + const fileName = this.fileName; if (urlEvaluationResult.resultType === ParsingResultType.EVALUATE_URL_SUCCESS) { for (let url of urlEvaluationResult.result) { this.restCalls.push({ method, url, line, fileName }); diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts index a90f30fb7a5e..fcdebd828486 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts @@ -11,16 +11,16 @@ interface SuperClass { interface ChildClass { superClass: string; name: string; - memberVariables: Map; + memberVariables: Map; parentMethodCalls: ParentMethodCalls[]; } interface ParentMethodCalls { name: string; - parameters: MemberVariable[]; + parameters: Attribute[]; } -interface MemberVariable { +interface Attribute { name: string; type: string; value?: string; @@ -28,16 +28,16 @@ interface MemberVariable { export class Preprocessor { public static PREPROCESSING_RESULTS = new Map(); - public static readonly pathPrefix = '' private readonly directoryPrefix = 'src/main/webapp/'; - private readonly fileToPreprocess: string; private ast: TSESTree.Program; - private memberVariables: Map = new Map(); + private memberVariables: Map = new Map(); - constructor(fileToPreprocess: string) { - this.fileToPreprocess = fileToPreprocess; - this.ast = Preprocessor.parseTypeScriptFile(Preprocessor.pathPrefix + this.fileToPreprocess); + /** + * @param ast - The abstract syntax tree (AST) of the processed file. + */ + constructor(ast: TSESTree.Program) { + this.ast = ast; } /** @@ -48,10 +48,6 @@ export class Preprocessor { * It also handles named exports that are class declarations. */ preprocessFile() { - if (this.ast.type !== 'Program') { - return; - } - this.ast.body.forEach((node) => { if (node.type === 'ClassDeclaration') { this.preprocessClass(node); @@ -254,11 +250,11 @@ export class Preprocessor { * which scans the class body for a property matching the parameter name and returns its value. * * @param parameterName - The name of the parameter whose value is to be found. - * @param filePath - The path to the TypeScript file (relative to the base directory set in `pathPrefix` and `directoryPrefix`) where the parameter value is to be searched. + * @param filePath - The path to the TypeScript file (relative to the base directory set in `directoryPrefix`) where the parameter value is to be searched. * @returns The value of the parameter if found; otherwise, an empty string. */ findParameterValueByParameterNameAndFilePath (parameterName: string, filePath: string): string { - const targetAST = Preprocessor.parseTypeScriptFile(`${Preprocessor.pathPrefix}${this.directoryPrefix}${filePath}.ts`); + const targetAST = Preprocessor.parseTypeScriptFile(`${this.directoryPrefix}${filePath}.ts`); for (const node of targetAST.body) { if (node.type === 'ExportNamedDeclaration' && node.declaration?.type === 'ClassDeclaration') { From f4deff34474c3f07e26f3980960e8c1a1da666be Mon Sep 17 00:00:00 2001 From: Florian Glombik <63976129+florian-glombik@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:05:15 +0200 Subject: [PATCH 02/10] Development: Use directive for programming repository button details in exercise detail overview (#9163) --- ...y-repository-buttons-detail.component.html | 25 +++++++++++ ...ary-repository-buttons-detail.component.ts | 20 +++++++++ ...g-repository-buttons-detail.component.html | 8 ++++ ...ing-repository-buttons-detail.component.ts | 16 +++++++ .../detail-overview-list.component.html | 45 ------------------- .../detail-overview-list.component.ts | 5 +-- .../app/detail-overview-list/detail.model.ts | 4 +- .../exercise-detail.directive.ts | 15 ++++++- .../exercise-detail.directive.spec.ts | 25 ++++++++++- 9 files changed, 110 insertions(+), 53 deletions(-) create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts diff --git a/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html new file mode 100644 index 000000000000..c22ec3d50039 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html @@ -0,0 +1,25 @@ +
    + @for (auxiliaryRepository of detail.data.auxiliaryRepositories; track auxiliaryRepository) { + @if (auxiliaryRepository.id && auxiliaryRepository.repositoryUri && detail.data.exerciseId) { +
  • + Repository: {{ auxiliaryRepository.name }} + + +
    + @if (!auxiliaryRepository.checkoutDirectory) { + + + } + + + +
    +
  • + } + } +
diff --git a/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts new file mode 100644 index 000000000000..e44170601ac7 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts @@ -0,0 +1,20 @@ +import { Component, Input } from '@angular/core'; +import { NoDataComponent } from 'app/shared/no-data-component'; +import { RouterModule } from '@angular/router'; +import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module'; +import { ArtemisProgrammingExerciseActionsModule } from 'app/exercises/programming/shared/actions/programming-exercise-actions.module'; +import { ProgrammingAuxiliaryRepositoryButtonsDetail } from 'app/detail-overview-list/detail.model'; +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; +import { ArtemisSharedModule } from 'app/shared/shared.module'; + +@Component({ + selector: 'jhi-programming-auxiliary-repository-buttons-detail', + templateUrl: 'programming-auxiliary-repository-buttons-detail.component.html', + standalone: true, + imports: [NoDataComponent, RouterModule, ArtemisSharedComponentModule, ArtemisProgrammingExerciseActionsModule, ArtemisSharedModule], +}) +export class ProgrammingAuxiliaryRepositoryButtonsDetailComponent { + @Input() detail: ProgrammingAuxiliaryRepositoryButtonsDetail; + + readonly faExclamationTriangle = faExclamationTriangle; +} diff --git a/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html new file mode 100644 index 000000000000..95f0a53976b1 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html @@ -0,0 +1,8 @@ +@if (detail.data.participation?.repositoryUri && detail.data.exerciseId) { +
+ + +
+} @else { + +} diff --git a/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts new file mode 100644 index 000000000000..21676685fed1 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts @@ -0,0 +1,16 @@ +import { Component, Input } from '@angular/core'; +import type { ProgrammingRepositoryButtonsDetail } from 'app/detail-overview-list/detail.model'; +import { NoDataComponent } from 'app/shared/no-data-component'; +import { RouterModule } from '@angular/router'; +import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module'; +import { ArtemisProgrammingExerciseActionsModule } from 'app/exercises/programming/shared/actions/programming-exercise-actions.module'; + +@Component({ + selector: 'jhi-programming-repository-buttons-detail', + templateUrl: 'programming-repository-buttons-detail.component.html', + standalone: true, + imports: [NoDataComponent, RouterModule, ArtemisSharedComponentModule, ArtemisProgrammingExerciseActionsModule], +}) +export class ProgrammingRepositoryButtonsDetailComponent { + @Input() detail: ProgrammingRepositoryButtonsDetail; +} diff --git a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html index 29ec5888ceae..ae8ce9674c34 100644 --- a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html +++ b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html @@ -15,51 +15,6 @@

{{ section } @switch (detail.type) { - @case (DetailType.ProgrammingRepositoryButtons) { -
- @if (detail.data.participation?.repositoryUri && detail.data.exerciseId) { -
- - -
- } @else { - - } -
- } - @case (DetailType.ProgrammingAuxiliaryRepositoryButtons) { -
-
    - @for (auxiliaryRepository of detail.data.auxiliaryRepositories; track auxiliaryRepository) { - @if (auxiliaryRepository.id && auxiliaryRepository.repositoryUri && detail.data.exerciseId) { -
  • - Repository: {{ auxiliaryRepository.name }} - - -
    - @if (!auxiliaryRepository.checkoutDirectory) { - - - } - - - -
    -
  • - } - } -
-
- } @case (DetailType.ProgrammingTestStatus) {
@if (detail.data.participation) { diff --git a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts index b7532ea79cb9..7f98ff940ef1 100644 --- a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts +++ b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { faArrowUpRightFromSquare, faCodeBranch, faCodeCompare, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; +import { faCodeCompare } from '@fortawesome/free-solid-svg-icons'; import { isEmpty } from 'lodash-es'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { ButtonSize, ButtonType, TooltipPlacement } from 'app/shared/components/button.component'; @@ -63,10 +63,7 @@ export class DetailOverviewListComponent implements OnInit, OnDestroy { headlinesRecord: Record; // icons - readonly faExclamationTriangle = faExclamationTriangle; readonly faCodeCompare = faCodeCompare; - readonly faArrowUpRightFromSquare = faArrowUpRightFromSquare; - readonly faCodeBranch = faCodeBranch; WARNING = ButtonType.WARNING; diff --git a/src/main/webapp/app/detail-overview-list/detail.model.ts b/src/main/webapp/app/detail-overview-list/detail.model.ts index 52c7012821aa..f8e8a5562044 100644 --- a/src/main/webapp/app/detail-overview-list/detail.model.ts +++ b/src/main/webapp/app/detail-overview-list/detail.model.ts @@ -83,7 +83,7 @@ interface ProgrammingIrisEnabledDetail extends DetailBase { data: { exercise?: ProgrammingExercise; course?: Course; disabled: boolean; subSettingsType: IrisSubSettingsType }; } -interface ProgrammingRepositoryButtonsDetail extends DetailBase { +export interface ProgrammingRepositoryButtonsDetail extends DetailBase { type: DetailType.ProgrammingRepositoryButtons; data: { exerciseId?: number; @@ -92,7 +92,7 @@ interface ProgrammingRepositoryButtonsDetail extends DetailBase { }; } -interface ProgrammingAuxiliaryRepositoryButtonsDetail extends DetailBase { +export interface ProgrammingAuxiliaryRepositoryButtonsDetail extends DetailBase { type: DetailType.ProgrammingAuxiliaryRepositoryButtons; data: { auxiliaryRepositories: AuxiliaryRepository[]; exerciseId?: number }; } diff --git a/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts b/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts index 069882e56eb4..9a0cd295b12e 100644 --- a/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts +++ b/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts @@ -5,6 +5,8 @@ import { TextDetailComponent } from 'app/detail-overview-list/components/text-de import { DateDetailComponent } from 'app/detail-overview-list/components/date-detail.component'; import { LinkDetailComponent } from 'app/detail-overview-list/components/link-detail.component'; import { BooleanDetailComponent } from 'app/detail-overview-list/components/boolean-detail.component'; +import { ProgrammingRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-repository-buttons-detail.component'; +import { ProgrammingAuxiliaryRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component'; @Directive({ selector: '[jhiExerciseDetail]', @@ -23,11 +25,22 @@ export class ExerciseDetailDirective implements OnInit, OnDestroy { } this.detail = this.detail as ShownDetail; - const detailTypeToComponent: { [key in DetailType]?: Type } = { + const detailTypeToComponent: { + [key in DetailType]?: Type< + | TextDetailComponent + | DateDetailComponent + | LinkDetailComponent + | BooleanDetailComponent + | ProgrammingRepositoryButtonsDetailComponent + | ProgrammingAuxiliaryRepositoryButtonsDetailComponent + >; + } = { [DetailType.Text]: TextDetailComponent, [DetailType.Date]: DateDetailComponent, [DetailType.Link]: LinkDetailComponent, [DetailType.Boolean]: BooleanDetailComponent, + [DetailType.ProgrammingRepositoryButtons]: ProgrammingRepositoryButtonsDetailComponent, + [DetailType.ProgrammingAuxiliaryRepositoryButtons]: ProgrammingAuxiliaryRepositoryButtonsDetailComponent, }; const detailComponent = detailTypeToComponent[this.detail.type]; diff --git a/src/test/javascript/spec/component/exercise-detail.directive.spec.ts b/src/test/javascript/spec/component/exercise-detail.directive.spec.ts index 4367413f636f..da435d3b9a84 100644 --- a/src/test/javascript/spec/component/exercise-detail.directive.spec.ts +++ b/src/test/javascript/spec/component/exercise-detail.directive.spec.ts @@ -1,13 +1,25 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ExerciseDetailDirective } from 'app/detail-overview-list/exercise-detail.directive'; import { Component, ViewChild } from '@angular/core'; -import type { BooleanDetail, DateDetail, Detail, LinkDetail, NotShownDetail, ShownDetail, TextDetail } from 'app/detail-overview-list/detail.model'; +import type { + BooleanDetail, + DateDetail, + Detail, + LinkDetail, + NotShownDetail, + ProgrammingAuxiliaryRepositoryButtonsDetail, + ProgrammingRepositoryButtonsDetail, + ShownDetail, + TextDetail, +} from 'app/detail-overview-list/detail.model'; import { TextDetailComponent } from 'app/detail-overview-list/components/text-detail.component'; import { MockComponent } from 'ng-mocks'; import { DetailType } from 'app/detail-overview-list/detail-overview-list.component'; import { DateDetailComponent } from 'app/detail-overview-list/components/date-detail.component'; import { LinkDetailComponent } from 'app/detail-overview-list/components/link-detail.component'; import { BooleanDetailComponent } from 'app/detail-overview-list/components/boolean-detail.component'; +import { ProgrammingRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-repository-buttons-detail.component'; +import { ProgrammingAuxiliaryRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component'; @Component({ template: `
`, @@ -63,6 +75,17 @@ describe('ExerciseDetailDirective', () => { it('should create BooleanDetail component', () => { checkComponentForDetailWasCreated({ type: DetailType.Boolean } as BooleanDetail, BooleanDetailComponent); }); + + it('should create ProgrammingRepositoryButtonsDetailComponent component', () => { + checkComponentForDetailWasCreated({ type: DetailType.ProgrammingRepositoryButtons } as ProgrammingRepositoryButtonsDetail, ProgrammingRepositoryButtonsDetailComponent); + }); + + it('should create ProgrammingAuxiliaryRepositoryButtonsDetailComponent component', () => { + checkComponentForDetailWasCreated( + { type: DetailType.ProgrammingAuxiliaryRepositoryButtons } as ProgrammingAuxiliaryRepositoryButtonsDetail, + ProgrammingAuxiliaryRepositoryButtonsDetailComponent, + ); + }); }); function checkComponentForDetailWasNotCreated(detailToBeChecked: NotShownDetail) { From 0d44cc17c99f62891ab486ded9a6ae68e92abc4a Mon Sep 17 00:00:00 2001 From: Benjamin Schmitz <66966223+bensofficial@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:17:16 +0200 Subject: [PATCH 03/10] Development: Enable http3 for test servers (#9232) --- docker/nginx.yml | 3 ++- docker/nginx/artemis-nginx.conf | 12 ++++++++++-- docker/nginx/artemis-server.conf | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docker/nginx.yml b/docker/nginx.yml index 0baaf14a0629..b7fbc47288cd 100644 --- a/docker/nginx.yml +++ b/docker/nginx.yml @@ -29,7 +29,8 @@ services: hard: 1048576 ports: - "80:80" - - "443:443" + - "443:443/tcp" + - "443:443/udp" # HTTP/3 - "7921:7921" # Git SSH # expose the port to make it reachable docker internally even if the external port mapping changes expose: diff --git a/docker/nginx/artemis-nginx.conf b/docker/nginx/artemis-nginx.conf index fa8f2d0376eb..cbc10836e993 100644 --- a/docker/nginx/artemis-nginx.conf +++ b/docker/nginx/artemis-nginx.conf @@ -18,8 +18,15 @@ server { } server { - listen 443 ssl http2; - listen [::]:443 ssl http2; + listen 443 ssl; + listen 443 quic reuseport; + listen [::]:443 ssl; + listen [::]:443 quic reuseport; + http2 on; + http3 on; + http3_hq on; + quic_retry on; + server_name _; ssl_certificate /certs/fullchain.pem; @@ -36,6 +43,7 @@ server { ssl_stapling on; ssl_stapling_verify on; # ssl_early_data on; + quic_gso on; include includes/artemis-server.conf; } diff --git a/docker/nginx/artemis-server.conf b/docker/nginx/artemis-server.conf index a9eb9d592d54..d00af9b9c3dd 100644 --- a/docker/nginx/artemis-server.conf +++ b/docker/nginx/artemis-server.conf @@ -23,6 +23,8 @@ location / { fastcgi_send_timeout 900s; fastcgi_read_timeout 900s; client_max_body_size 128M; + # used to advertise the availability of HTTP/3 + add_header alt-svc 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000'; } location /api/authenticate { From 93e5704fae99f638dfeb10d5b3d4ea8a28a7e1a8 Mon Sep 17 00:00:00 2001 From: Lucas Welscher Date: Wed, 21 Aug 2024 11:18:01 +0200 Subject: [PATCH 04/10] Communication: Fix link in email notification (#9212) --- .../domain/notification/NotificationTargetFactory.java | 6 +++--- .../artemis/notification/NotificationTargetFactoryTest.java | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java b/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java index 86a856dffce2..76f24a8456c4 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java @@ -339,11 +339,11 @@ public static String extractNotificationUrl(Notification notification, String ba * If the post is not associated with a conversation or messaging is disabled in the course, the URL leads to the communication page. * * @param post which information will be needed to create the URL - * @param baseUrl the prefix (depends on current set up (e.g. "http://localhost:9000/courses")) + * @param baseUrl the prefix (depends on current set up (e.g. "http://localhost:9000")) * @return viable URL to the notification related page */ public static String extractNotificationUrl(Post post, String baseUrl) { - // e.g. http://localhost:8080/courses/1/messages?conversationId=123 - return baseUrl + "/courses/" + post.getConversation().getCourse().getId() + "/messages?conversationId=" + post.getConversation().getId(); + // e.g. http://localhost:8080/courses/1/communication?conversationId=123 + return baseUrl + "/courses/" + post.getConversation().getCourse().getId() + "/communication?conversationId=" + post.getConversation().getId(); } } diff --git a/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java b/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java index 96b0db2daa28..c97014991558 100644 --- a/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java +++ b/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java @@ -58,8 +58,6 @@ class NotificationTargetFactoryTest { private static final String BASE_URL = "https://artemistest.ase.in.tum.de"; - private static final String MESSAGES_CONVERSATION = "messages?conversationId="; - private String resultingURL; private static final String PROBLEM_STATEMENT = "problem statement"; @@ -74,8 +72,8 @@ class NotificationTargetFactoryTest { // expected/correct URLs - // e.g. https://artemistest.ase.in.tum.de/courses/477/discussion?searchText=%232000 - private static final String EXPECTED_POST_URL = BASE_URL_COURSES_COURSE_ID + "/" + MESSAGES_CONVERSATION + CHANNEL_ID; + // e.g. https://artemistest.ase.in.tum.de/courses/477/communication?conversationId=2000 + private static final String EXPECTED_POST_URL = BASE_URL_COURSES_COURSE_ID + "/" + "communication?conversationId=" + CHANNEL_ID; // e.g. https://artemistest.ase.in.tum.de/courses/477/lectures/199 private static final String EXPECTED_ATTACHMENT_CHANGED_URL = BASE_URL_COURSES_COURSE_ID + "/" + LECTURES_TEXT + "/" + LECTURE_ID; From cf250f1fe814e033457ef721feb89015cf61b090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Wei=C3=9F?= Date: Wed, 21 Aug 2024 12:19:36 +0200 Subject: [PATCH 05/10] Communication: Fix tooltip translation for the tutor icon in the conversation member list (#9229) --- .../conversation-member-row.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts index 28e03c588910..5044543d4878 100644 --- a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts +++ b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts @@ -246,7 +246,7 @@ export class ConversationMemberRowComponent implements OnInit, OnDestroy { this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'instructor'); } else if (this.conversationMember.isEditor || this.conversationMember.isTeachingAssistant) { this.userIcon = faUserCheck; - this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'ta'); + this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'tutor'); } else { this.userIcon = faUser; this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'student'); From 360027f0d58a61700e90f7434e273b8e6f0f31ef Mon Sep 17 00:00:00 2001 From: Johannes Wiest Date: Wed, 21 Aug 2024 12:20:33 +0200 Subject: [PATCH 06/10] Lectures: Add bottom padding in course details (#9196) --- .../course-lectures/course-lecture-details.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html b/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html index dc7e8b2eefcf..31e417b42160 100644 --- a/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html +++ b/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html @@ -36,7 +36,7 @@

-
+
@if (lecture.description) {
@@ -61,8 +61,8 @@

{{ 'artemisApp.courseOverview.lectureDetails.lectureUnits' | artemisTranslat

} @for (lectureUnit of lectureUnits; track lectureUnit) { -
-
+
+
@switch (lectureUnit.type) { @case (LectureUnitType.EXERCISE) { From fc5e849cf01acaa8d54965285c820fa4fa05489c Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour <58034472+BBesrour@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:21:18 +0200 Subject: [PATCH 07/10] Programming exercises: Fix import from file not importing build values (#9192) --- .../entities/programming-exercise.model.ts | 4 +- .../programming-exercise-detail.component.ts | 10 +-- .../programming-exercise-update.component.ts | 14 ++-- ...se-custom-aeolus-build-plan.component.html | 6 +- ...cise-custom-aeolus-build-plan.component.ts | 54 +++++++------ ...-exercise-custom-build-plan.component.html | 4 +- ...ng-exercise-custom-build-plan.component.ts | 64 ++++++++------- .../shared/service/aeolus.service.ts | 14 ++-- ...custom-aeolus-build-plan.component.spec.ts | 81 +++++++++++++------ ...ercise-custom-build-plan.component.spec.ts | 67 ++++++++++----- ...gramming-exercise-update.component.spec.ts | 4 +- 11 files changed, 196 insertions(+), 126 deletions(-) diff --git a/src/main/webapp/app/entities/programming-exercise.model.ts b/src/main/webapp/app/entities/programming-exercise.model.ts index 7b72d222cfc4..f8a37efc1b6e 100644 --- a/src/main/webapp/app/entities/programming-exercise.model.ts +++ b/src/main/webapp/app/entities/programming-exercise.model.ts @@ -66,7 +66,7 @@ export class ProgrammingExerciseBuildConfig { public checkoutPath?: string; public timeoutSeconds?: number; public dockerFlags?: string; - public windFile?: WindFile; + public windfile?: WindFile; public testwiseCoverageEnabled?: boolean; constructor() { @@ -176,7 +176,7 @@ export function copyBuildConfigFromExerciseJson(exerciseJson: ProgrammingExercis buildConfig.buildPlanConfiguration = exerciseJson.buildPlanConfiguration ?? ''; buildConfig.checkoutSolutionRepository = exerciseJson.checkoutSolutionRepository ?? false; buildConfig.timeoutSeconds = exerciseJson.timeoutSeconds ?? 0; - buildConfig.windFile = exerciseJson.windFile ?? undefined; + buildConfig.windfile = exerciseJson.windfile ?? undefined; buildConfig.buildScript = exerciseJson.buildScript ?? ''; buildConfig.testwiseCoverageEnabled = exerciseJson.testwiseCoverageEnabled ?? false; buildConfig.dockerFlags = exerciseJson.dockerFlags ?? ''; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts index 55dec97cbd6e..a2f1e2174227 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts @@ -456,13 +456,13 @@ export class ProgrammingExerciseDetailComponent implements OnInit, OnDestroy { }, }, !!exercise.buildConfig?.buildScript && - !!exercise.buildConfig?.windFile?.metadata?.docker?.image && { + !!exercise.buildConfig?.windfile?.metadata?.docker?.image && { type: DetailType.Text, title: 'artemisApp.programmingExercise.dockerImage', - data: { text: exercise.buildConfig?.windFile?.metadata?.docker?.image }, + data: { text: exercise.buildConfig?.windfile?.metadata?.docker?.image }, }, !!exercise.buildConfig?.buildScript && - !!exercise.buildConfig?.windFile?.metadata?.docker?.image && { + !!exercise.buildConfig?.windfile?.metadata?.docker?.image && { type: DetailType.Markdown, title: 'artemisApp.programmingExercise.script', titleHelpText: 'artemisApp.programmingExercise.revertToTemplateBuildPlan', @@ -752,8 +752,8 @@ export class ProgrammingExerciseDetailComponent implements OnInit, OnDestroy { * @param exercise the programming exercise to check */ checkAndSetWindFile(exercise: ProgrammingExercise) { - if (exercise.buildConfig && exercise.buildConfig?.buildPlanConfiguration && !exercise.buildConfig?.windFile) { - exercise.buildConfig!.windFile = this.aeolusService.parseWindFile(exercise.buildConfig?.buildPlanConfiguration); + if (exercise.buildConfig && exercise.buildConfig?.buildPlanConfiguration && !exercise.buildConfig?.windfile) { + exercise.buildConfig!.windfile = this.aeolusService.parseWindFile(exercise.buildConfig?.buildPlanConfiguration); } } diff --git a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts index 629b1bc07d26..755a6241cfca 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts @@ -265,7 +265,7 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest this.withDependenciesValue = false; this.buildPlanLoaded = false; if (this.programmingExercise.buildConfig) { - this.programmingExercise.buildConfig.windFile = undefined; + this.programmingExercise.buildConfig.windfile = undefined; this.programmingExercise.buildConfig.buildPlanConfiguration = undefined; } else { this.programmingExercise.buildConfig = new ProgrammingExerciseBuildConfig(); @@ -390,7 +390,7 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest this.activatedRoute.data.subscribe(({ programmingExercise }) => { this.programmingExercise = programmingExercise; if (this.programmingExercise.buildConfig?.buildPlanConfiguration) { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig!.buildPlanConfiguration); + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig!.buildPlanConfiguration); } this.backupExercise = cloneDeep(this.programmingExercise); this.selectedProgrammingLanguageValue = this.programmingExercise.programmingLanguage!; @@ -615,15 +615,15 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest */ saveExercise() { // trim potential whitespaces that can lead to issues - if (this.programmingExercise.buildConfig!.windFile?.metadata?.docker?.image) { - this.programmingExercise.buildConfig!.windFile.metadata.docker.image = this.programmingExercise.buildConfig!.windFile.metadata.docker.image.trim(); + if (this.programmingExercise.buildConfig!.windfile?.metadata?.docker?.image) { + this.programmingExercise.buildConfig!.windfile.metadata.docker.image = this.programmingExercise.buildConfig!.windfile.metadata.docker.image.trim(); } - if (this.programmingExercise.customizeBuildPlanWithAeolus) { - this.programmingExercise.buildConfig!.buildPlanConfiguration = this.aeolusService.serializeWindFile(this.programmingExercise.buildConfig!.windFile!); + if (this.programmingExercise.customizeBuildPlanWithAeolus || this.isImportFromFile) { + this.programmingExercise.buildConfig!.buildPlanConfiguration = this.aeolusService.serializeWindFile(this.programmingExercise.buildConfig!.windfile!); } else { this.programmingExercise.buildConfig!.buildPlanConfiguration = undefined; - this.programmingExercise.buildConfig!.windFile = undefined; + this.programmingExercise.buildConfig!.windfile = undefined; } // If the programming exercise has a submission policy with a NONE type, the policy is removed altogether if (this.programmingExercise.submissionPolicy && this.programmingExercise.submissionPolicy.type === SubmissionPolicyType.NONE) { diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html index aa9a31a9dfcf..bcfd1a078ac7 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html @@ -6,16 +6,16 @@
@if (programmingExercise.customizeBuildPlanWithAeolus) {
- @if (programmingExercise.buildConfig?.windFile && programmingExercise.buildConfig?.windFile?.metadata && programmingExercise.buildConfig?.windFile?.metadata?.docker) { + @if (programmingExercise.buildConfig?.windfile && programmingExercise.buildConfig?.windfile?.metadata && programmingExercise.buildConfig?.windfile?.metadata?.docker) { }
- @for (action of this.programmingExercise.buildConfig?.windFile?.actions; track action) { + @for (action of this.programmingExercise.buildConfig?.windfile?.actions; track action) {

{{ action.name }}

diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts index 92f3a3a31443..4f51ccd37432 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts @@ -42,7 +42,8 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan ngOnChanges(changes: SimpleChanges) { if (changes.programmingExerciseCreationConfig || changes.programmingExercise) { if (this.shouldReloadTemplate()) { - this.loadAeolusTemplate(); + const isImportFromFile = changes.programmingExerciseCreationConfig?.currentValue?.isImportFromFile ?? false; + this.loadAeolusTemplate(isImportFromFile); } } } @@ -62,20 +63,21 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan * @private */ resetCustomBuildPlan() { - this.programmingExercise.buildConfig!.windFile = undefined; + this.programmingExercise.buildConfig!.windfile = undefined; this.programmingExercise.buildConfig!.buildPlanConfiguration = undefined; } /** * Loads the predefined template for the selected programming language and project type * if there is one available. + * @param isImportFromFile whether the exercise is imported from a file * @private */ - loadAeolusTemplate() { - if (this.programmingExercise?.id) { - if (!this.programmingExerciseCreationConfig.buildPlanLoaded && !this.programmingExercise.buildConfig?.windFile) { + loadAeolusTemplate(isImportFromFile: boolean = false) { + if (this.programmingExercise?.id || isImportFromFile) { + if (!this.programmingExerciseCreationConfig.buildPlanLoaded && !this.programmingExercise.buildConfig?.windfile) { if (this.programmingExercise.buildConfig?.buildPlanConfiguration) { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig?.buildPlanConfiguration); + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig?.buildPlanConfiguration); } this.programmingExerciseCreationConfig.buildPlanLoaded = true; } @@ -90,16 +92,18 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan this.staticCodeAnalysisEnabled = this.programmingExercise.staticCodeAnalysisEnabled; this.sequentialTestRuns = this.programmingExercise.buildConfig?.sequentialTestRuns; this.testwiseCoverageEnabled = this.programmingExercise.buildConfig?.testwiseCoverageEnabled; - this.aeolusService - .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) - .subscribe({ - next: (file) => { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(file); - }, - error: () => { - this.programmingExercise.buildConfig!.windFile = undefined; - }, - }); + if (!isImportFromFile || !this.programmingExercise.buildConfig?.windfile) { + this.aeolusService + .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) + .subscribe({ + next: (file) => { + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(file); + }, + error: () => { + this.programmingExercise.buildConfig!.windfile = undefined; + }, + }); + } this.programmingExerciseCreationConfig.buildPlanLoaded = true; } @@ -110,7 +114,7 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan faQuestionCircle = faQuestionCircle; protected getActionScript(action: string): string { - const foundAction: BuildAction | undefined = this.programmingExercise.buildConfig?.windFile?.actions.find((a) => a.name === action); + const foundAction: BuildAction | undefined = this.programmingExercise.buildConfig?.windfile?.actions.find((a) => a.name === action); if (foundAction && foundAction instanceof ScriptAction) { return (foundAction as ScriptAction).script; } @@ -118,12 +122,12 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } changeActiveAction(action: string): void { - if (!this.programmingExercise.buildConfig?.windFile) { + if (!this.programmingExercise.buildConfig?.windfile) { return; } this.code = this.getActionScript(action); - this.active = this.programmingExercise.buildConfig?.windFile.actions.find((a) => a.name === action); + this.active = this.programmingExercise.buildConfig?.windfile.actions.find((a) => a.name === action); this.isScriptAction = this.active instanceof ScriptAction; if (this.isScriptAction && this.editor) { this.editor.setText(this.code); @@ -131,8 +135,8 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } deleteAction(action: string): void { - if (this.programmingExercise.buildConfig?.windFile) { - this.programmingExercise.buildConfig!.windFile.actions = this.programmingExercise.buildConfig?.windFile.actions.filter((a) => a.name !== action); + if (this.programmingExercise.buildConfig?.windfile) { + this.programmingExercise.buildConfig!.windfile.actions = this.programmingExercise.buildConfig?.windfile.actions.filter((a) => a.name !== action); if (this.active?.name === action) { this.active = undefined; this.code = ''; @@ -141,12 +145,12 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } addAction(action: string): void { - if (this.programmingExercise.buildConfig?.windFile) { + if (this.programmingExercise.buildConfig?.windfile) { const newAction = new ScriptAction(); newAction.script = '#!/bin/bash\n\n# Add your custom build plan action here\n\nexit 0'; newAction.name = action; newAction.runAlways = false; - this.programmingExercise.buildConfig?.windFile.actions.push(newAction); + this.programmingExercise.buildConfig?.windfile.actions.push(newAction); this.changeActiveAction(action); } } @@ -194,9 +198,9 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } setDockerImage(dockerImage: string) { - if (!this.programmingExercise.buildConfig?.windFile || !this.programmingExercise.buildConfig?.windFile.metadata.docker) { + if (!this.programmingExercise.buildConfig?.windfile || !this.programmingExercise.buildConfig?.windfile.metadata.docker) { return; } - this.programmingExercise.buildConfig!.windFile.metadata.docker.image = dockerImage.trim(); + this.programmingExercise.buildConfig!.windfile.metadata.docker.image = dockerImage.trim(); } } diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html index 2f05f5d16dd4..0c0e2c702af7 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html @@ -6,9 +6,9 @@
@if (programmingExercise.customizeBuildPlanWithAeolus) {
- @if (programmingExercise.buildConfig?.windFile && programmingExercise.buildConfig?.windFile?.metadata && programmingExercise.buildConfig?.windFile?.metadata?.docker) { + @if (programmingExercise.buildConfig?.windfile && programmingExercise.buildConfig?.windfile?.metadata && programmingExercise.buildConfig?.windfile?.metadata?.docker) { } diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts index b87916c9c3fd..437d2f56d57e 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts @@ -22,6 +22,7 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { staticCodeAnalysisEnabled?: boolean; sequentialTestRuns?: boolean; testwiseCoverageEnabled?: boolean; + isImportFromFile: boolean = false; constructor(private aeolusService: AeolusService) {} @@ -32,7 +33,7 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { this._editor = value; if (this._editor) { this.setupEditor(); - if (this.programmingExercise.id) { + if (this.programmingExercise.id || this.isImportFromFile) { this.code = this.programmingExercise.buildConfig?.buildScript || ''; } this._editor.setText(this.code); @@ -42,7 +43,8 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { ngOnChanges(changes: SimpleChanges) { if (changes.programmingExerciseCreationConfig || changes.programmingExercise) { if (this.shouldReloadTemplate()) { - this.loadAeolusTemplate(); + const isImportFromFile = changes.programmingExerciseCreationConfig?.currentValue?.isImportFromFile ?? false; + this.loadAeolusTemplate(isImportFromFile); } } } @@ -63,7 +65,7 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { * @private */ resetCustomBuildPlan() { - this.programmingExercise.buildConfig!.windFile = undefined; + this.programmingExercise.buildConfig!.windfile = undefined; this.programmingExercise.buildConfig!.buildPlanConfiguration = undefined; this.programmingExercise.buildConfig!.buildScript = undefined; } @@ -71,9 +73,10 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { /** * Loads the predefined template for the selected programming language and project type * if there is one available. + * @param isImportFromFile whether the exercise is imported from a file * @private */ - loadAeolusTemplate() { + loadAeolusTemplate(isImportFromFile: boolean = false) { if (!this.programmingExercise.programmingLanguage) { return; } @@ -82,31 +85,36 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { this.staticCodeAnalysisEnabled = this.programmingExercise.staticCodeAnalysisEnabled; this.sequentialTestRuns = this.programmingExercise.buildConfig?.sequentialTestRuns; this.testwiseCoverageEnabled = this.programmingExercise.buildConfig?.testwiseCoverageEnabled; - this.aeolusService - .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) - .subscribe({ - next: (file) => { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(file); - }, - error: () => { - this.programmingExercise.buildConfig!.windFile = undefined; - }, - }); + this.isImportFromFile = isImportFromFile; + if (!isImportFromFile || !this.programmingExercise.buildConfig?.windfile) { + this.aeolusService + .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) + .subscribe({ + next: (file) => { + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(file); + }, + error: () => { + this.programmingExercise.buildConfig!.windfile = undefined; + }, + }); + } this.programmingExerciseCreationConfig.buildPlanLoaded = true; - if (!this.programmingExercise.buildConfig?.windFile) { + if (!this.programmingExercise.buildConfig?.windfile) { this.resetCustomBuildPlan(); } - this.aeolusService - .getAeolusTemplateScript(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) - .subscribe({ - next: (file: string) => { - this.codeChanged(file); - this.editor?.setText(file); - }, - error: () => { - this.programmingExercise.buildConfig!.buildScript = undefined; - }, - }); + if (!isImportFromFile || !this.programmingExercise.buildConfig?.buildScript) { + this.aeolusService + .getAeolusTemplateScript(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) + .subscribe({ + next: (file: string) => { + this.codeChanged(file); + this.editor?.setText(file); + }, + error: () => { + this.programmingExercise.buildConfig!.buildScript = undefined; + }, + }); + } if (!this.programmingExercise.buildConfig?.buildScript) { this.resetCustomBuildPlan(); } @@ -134,9 +142,9 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { } setDockerImage(dockerImage: string) { - if (!this.programmingExercise.buildConfig?.windFile || !this.programmingExercise.buildConfig?.windFile.metadata.docker) { + if (!this.programmingExercise.buildConfig?.windfile || !this.programmingExercise.buildConfig?.windfile.metadata.docker) { return; } - this.programmingExercise.buildConfig!.windFile.metadata.docker.image = dockerImage.trim(); + this.programmingExercise.buildConfig!.windfile.metadata.docker.image = dockerImage.trim(); } } diff --git a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts index 5871d4ca94f1..e13138c55c04 100644 --- a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts @@ -51,7 +51,7 @@ export class AeolusService { parseWindFile(file: string): WindFile | undefined { try { const templateFile: WindFile = JSON.parse(file); - const windFile: WindFile = Object.assign(new WindFile(), templateFile); + const windfile: WindFile = Object.assign(new WindFile(), templateFile); const actions: BuildAction[] = []; templateFile.actions.forEach((anyAction: any) => { let action: BuildAction | undefined; @@ -71,11 +71,11 @@ export class AeolusService { } }); // somehow, the returned content may have a scriptActions field, which is not a field of the WindFile class - if ('scriptActions' in windFile) { - delete windFile['scriptActions']; + if ('scriptActions' in windfile) { + delete windfile['scriptActions']; } - windFile.actions = actions; - return windFile; + windfile.actions = actions; + return windfile; } catch (SyntaxError) { return undefined; } @@ -100,8 +100,8 @@ export class AeolusService { }; } - serializeWindFile(windFile: WindFile): string { - return JSON.stringify(windFile, this.replacer); + serializeWindFile(windfile: WindFile): string { + return JSON.stringify(windfile, this.replacer); } /** diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts index 93e57264bd42..fdc1d42c64b1 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts @@ -33,7 +33,7 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { const route = { snapshot: { paramMap: convertToParamMap({ courseId: course.id }) } } as any as ActivatedRoute; let programmingExercise = new ProgrammingExercise(course, undefined); - let windFile: WindFile = new WindFile(); + let windfile: WindFile = new WindFile(); let actions: BuildAction[] = []; let gradleBuildAction: ScriptAction = new ScriptAction(); let cleanBuildAction: ScriptAction = new ScriptAction(); @@ -45,11 +45,11 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { beforeEach(() => { programmingExercise = new ProgrammingExercise(course, undefined); programmingExercise.customizeBuildPlanWithAeolus = true; - windFile = new WindFile(); + windfile = new WindFile(); const metadata = new WindMetadata(); metadata.docker = new DockerConfiguration(); metadata.docker.image = 'testImage'; - windFile.metadata = metadata; + windfile.metadata = metadata; actions = []; gradleBuildAction = new ScriptAction(); gradleBuildAction.name = 'gradle'; @@ -65,8 +65,8 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { actions.push(gradleBuildAction); actions.push(cleanBuildAction); actions.push(platformAction); - windFile.actions = actions; - programmingExercise.buildConfig!.windFile = windFile; + windfile.actions = actions; + programmingExercise.buildConfig!.windfile = windfile; TestBed.configureTestingModule({ imports: [ArtemisTestModule], @@ -114,19 +114,19 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { it('should delete action', () => { comp.deleteAction('gradle'); - const size = programmingExercise.buildConfig?.windFile?.actions.length; + const size = programmingExercise.buildConfig?.windfile?.actions.length; expect(size).toBeDefined(); const realSize = size!; - expect(programmingExercise.buildConfig?.windFile?.actions.length).toBe(realSize); + expect(programmingExercise.buildConfig?.windfile?.actions.length).toBe(realSize); comp.deleteAction('clean'); - expect(programmingExercise.buildConfig?.windFile?.actions.length).toBe(realSize - 1); + expect(programmingExercise.buildConfig?.windfile?.actions.length).toBe(realSize - 1); }); it('should add action', () => { - const size = programmingExercise.buildConfig?.windFile?.actions.length; + const size = programmingExercise.buildConfig?.windfile?.actions.length; expect(size).toBeDefined(); comp.addAction('gradle clean'); - expect(programmingExercise.buildConfig?.windFile?.actions.length).toBe(size! + 1); + expect(programmingExercise.buildConfig?.windfile?.actions.length).toBe(size! + 1); }); it('should accept editor', () => { @@ -152,7 +152,7 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should do nothing without a Windfile', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; comp.code = 'this should not change'; comp.changeActiveAction(''); expect(comp.code).toBe('this should not change'); @@ -206,12 +206,12 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should reset buildplan', () => { - programmingExercise.buildConfig!.windFile = windFile; + programmingExercise.buildConfig!.windfile = windfile; programmingExercise.buildConfig!.buildPlanConfiguration = 'some build plan'; - expect(programmingExercise.buildConfig?.windFile).toBeDefined(); + expect(programmingExercise.buildConfig?.windfile).toBeDefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeDefined(); comp.resetCustomBuildPlan(); - expect(programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeUndefined(); }); @@ -264,28 +264,28 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should update windfile', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_AEOLUS; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; - jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windFile)))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeDefined(); - expect(comp.programmingExercise.buildConfig?.windFile).toEqual(windFile); + expect(comp.programmingExercise.buildConfig?.windfile).toBeDefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toEqual(windfile); }); it('should call this.resetCustomBuildPlan', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_AEOLUS; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; const resetSpy = jest.spyOn(comp, 'resetCustomBuildPlan'); jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(resetSpy).toHaveBeenCalled(); }); it('should parse windfile correctly', () => { - const parsedWindFile = mockAeolusService.parseWindFile(mockAeolusService.serializeWindFile(windFile)); + const parsedWindFile = mockAeolusService.parseWindFile(mockAeolusService.serializeWindFile(windfile)); expect(parsedWindFile).toBeDefined(); expect(parsedWindFile?.actions.length).toBe(3); expect(parsedWindFile?.actions[0]).toBeInstanceOf(ScriptAction); @@ -341,12 +341,41 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should set docker image correctly', () => { - comp.programmingExercise.buildConfig!.windFile = windFile; - comp.programmingExercise.buildConfig!.windFile.metadata.docker.image = 'old'; + comp.programmingExercise.buildConfig!.windfile = windfile; + comp.programmingExercise.buildConfig!.windfile.metadata.docker.image = 'old'; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile?.metadata.docker.image).toBe('testImage'); - comp.programmingExercise.buildConfig!.windFile = undefined; + expect(comp.programmingExercise.buildConfig?.windfile?.metadata.docker.image).toBe('testImage'); + comp.programmingExercise.buildConfig!.windfile = undefined; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); + }); + + it('should not call getAeolusTemplateScript when import from file if script present', () => { + comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; + comp.programmingExerciseCreationConfig.isImportFromFile = true; + programmingExercise.buildConfig!.buildScript = 'echo "test"'; + jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); + comp.ngOnChanges({ + programmingExercise: { + currentValue: programmingExercise, + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + programmingExerciseCreationConfig: { + currentValue: JSON.parse(JSON.stringify(comp.programmingExerciseCreationConfig)), + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + }); + expect(mockAeolusService.getAeolusTemplateScript).not.toHaveBeenCalled(); + expect(mockAeolusService.getAeolusTemplateFile).not.toHaveBeenCalled(); + expect(comp.programmingExercise.buildConfig?.buildScript).toBe('echo "test"'); }); }); diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts index 8ce4d5ab6f3c..fe342f5eac56 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts @@ -33,7 +33,7 @@ describe('ProgrammingExercise Custom Build Plan', () => { const route = { snapshot: { paramMap: convertToParamMap({ courseId: course.id }) } } as any as ActivatedRoute; let programmingExercise = new ProgrammingExercise(course, undefined); - let windFile: WindFile = new WindFile(); + let windfile: WindFile = new WindFile(); let actions: BuildAction[] = []; let gradleBuildAction: ScriptAction = new ScriptAction(); let cleanBuildAction: ScriptAction = new ScriptAction(); @@ -45,11 +45,11 @@ describe('ProgrammingExercise Custom Build Plan', () => { beforeEach(() => { programmingExercise = new ProgrammingExercise(course, undefined); programmingExercise.customizeBuildPlanWithAeolus = true; - windFile = new WindFile(); + windfile = new WindFile(); const metadata = new WindMetadata(); metadata.docker = new DockerConfiguration(); metadata.docker.image = 'testImage'; - windFile.metadata = metadata; + windfile.metadata = metadata; actions = []; gradleBuildAction = new ScriptAction(); gradleBuildAction.name = 'gradle'; @@ -63,8 +63,8 @@ describe('ProgrammingExercise Custom Build Plan', () => { actions.push(gradleBuildAction); actions.push(cleanBuildAction); actions.push(platformAction); - windFile.actions = actions; - programmingExercise.buildConfig!.windFile = windFile; + windfile.actions = actions; + programmingExercise.buildConfig!.windfile = windfile; TestBed.configureTestingModule({ imports: [ArtemisTestModule], @@ -127,12 +127,12 @@ describe('ProgrammingExercise Custom Build Plan', () => { }); it('should reset buildplan', () => { - programmingExercise.buildConfig!.windFile = windFile; + programmingExercise.buildConfig!.windfile = windfile; programmingExercise.buildConfig!.buildPlanConfiguration = 'some build plan'; - expect(programmingExercise.buildConfig?.windFile).toBeDefined(); + expect(programmingExercise.buildConfig?.windfile).toBeDefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeDefined(); comp.resetCustomBuildPlan(); - expect(programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeUndefined(); }); @@ -185,23 +185,23 @@ describe('ProgrammingExercise Custom Build Plan', () => { }); it('should update windfile', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_LOCALCI; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; - jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windFile)))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.next("echo 'test'"))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeDefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeDefined(); }); it('should call this.resetCustomBuildPlan', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_LOCALCI; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; const resetSpy = jest.spyOn(comp, 'resetCustomBuildPlan'); jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(resetSpy).toHaveBeenCalled(); }); @@ -211,7 +211,7 @@ describe('ProgrammingExercise Custom Build Plan', () => { comp.programmingExercise.id = 1; jest.spyOn(comp, 'resetCustomBuildPlan'); jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.next("echo 'test'"))); - jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windFile)))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); comp.loadAeolusTemplate(); expect(comp.resetCustomBuildPlan).not.toHaveBeenCalled(); expect(comp.programmingExercise.buildConfig?.buildScript).toBe("echo 'test'"); @@ -243,12 +243,41 @@ describe('ProgrammingExercise Custom Build Plan', () => { }); it('should set docker image correctly', () => { - comp.programmingExercise.buildConfig!.windFile = windFile; - comp.programmingExercise.buildConfig!.windFile.metadata.docker.image = 'old'; + comp.programmingExercise.buildConfig!.windfile = windfile; + comp.programmingExercise.buildConfig!.windfile.metadata.docker.image = 'old'; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile?.metadata.docker.image).toBe('testImage'); - comp.programmingExercise.buildConfig!.windFile = undefined; + expect(comp.programmingExercise.buildConfig?.windfile?.metadata.docker.image).toBe('testImage'); + comp.programmingExercise.buildConfig!.windfile = undefined; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); + }); + + it('should not call getAeolusTemplateScript when import from file if script present', () => { + comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; + comp.programmingExerciseCreationConfig.isImportFromFile = true; + programmingExercise.buildConfig!.buildScript = 'echo "test"'; + jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); + comp.ngOnChanges({ + programmingExercise: { + currentValue: programmingExercise, + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + programmingExerciseCreationConfig: { + currentValue: JSON.parse(JSON.stringify(comp.programmingExerciseCreationConfig)), + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + }); + expect(mockAeolusService.getAeolusTemplateScript).not.toHaveBeenCalled(); + expect(mockAeolusService.getAeolusTemplateFile).not.toHaveBeenCalled(); + expect(comp.programmingExercise.buildConfig?.buildScript).toBe('echo "test"'); }); }); diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts index b5664b00adb5..df1e7b8924b0 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts @@ -438,14 +438,14 @@ describe('ProgrammingExerciseUpdateComponent', () => { // WHEN fixture.detectChanges(); comp.programmingExercise.buildConfig!.buildPlanConfiguration = 'some custom build definition'; - comp.programmingExercise.buildConfig!.windFile = new WindFile(); + comp.programmingExercise.buildConfig!.windfile = new WindFile(); tick(); comp.onProgrammingLanguageChange(ProgrammingLanguage.C); comp.onProjectTypeChange(ProjectType.FACT); // THEN expect(comp.programmingExercise.buildConfig?.buildPlanConfiguration).toBeUndefined(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); })); }); From b75396d8f0b29b77cdb5efee8df77c7e2ae81ec3 Mon Sep 17 00:00:00 2001 From: Patrik Zander <38403547+pzdr7@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:31:12 +0200 Subject: [PATCH 08/10] Programming exercises: Remove the legacy README.md handling (#9220) --- .../code-editor-file-browser.component.ts | 11 +- ...gramming-exercise-instruction.component.ts | 26 +---- ...code-editor-file-browser.component.spec.ts | 105 ++++++++++++++++- ...ing-exercise-instruction.component.spec.ts | 106 ++---------------- 4 files changed, 116 insertions(+), 132 deletions(-) diff --git a/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts b/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts index 52fa1c7dbd28..16cd6c22176b 100644 --- a/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts @@ -515,8 +515,6 @@ export class CodeEditorFileBrowserComponent implements OnInit, OnChanges, AfterV fromPairs( toPairs(files) .filter(([fileName, fileType]) => this.allowHiddenFiles || CodeEditorFileBrowserComponent.shouldDisplayFile(fileName, fileType)) - // Filter Readme file that was historically in the student's assignment repo - .filter(([value]) => !value.includes('README.md')) // Filter root folder .filter(([value]) => value), ), @@ -527,14 +525,7 @@ export class CodeEditorFileBrowserComponent implements OnInit, OnChanges, AfterV loadFilesWithInformationAboutChange(): Observable<{ [fileName: string]: boolean }> { return this.repositoryFileService.getFilesWithInformationAboutChange().pipe( - rxMap((files) => - fromPairs( - toPairs(files) - .filter(([filename]) => this.allowHiddenFiles || CodeEditorFileBrowserComponent.shouldDisplayFile(filename, FileType.FILE)) - // Filter Readme file that was historically in the student's assignment repo - .filter(([value]) => !value.includes('README.md')), - ), - ), + rxMap((files) => fromPairs(toPairs(files).filter(([filename]) => this.allowHiddenFiles || CodeEditorFileBrowserComponent.shouldDisplayFile(filename, FileType.FILE)))), catchError(() => throwError(() => new Error('couldNotBeRetrieved'))), ); } diff --git a/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts b/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts index 4fd960bbbe2d..75e060446c19 100644 --- a/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts @@ -27,7 +27,6 @@ import { TaskArray } from 'app/exercises/programming/shared/instructions-render/ import { Participation } from 'app/entities/participation/participation.model'; import { Feedback } from 'app/entities/feedback.model'; import { ResultService } from 'app/exercises/shared/result/result.service'; -import { RepositoryFileService } from 'app/exercises/shared/result/repository.service'; import { problemStatementHasChanged } from 'app/exercises/shared/exercise/exercise.utils'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { Result } from 'app/entities/result.model'; @@ -51,7 +50,7 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes @Input() public participation: Participation; @Input() generateHtmlEvents: Observable; @Input() personalParticipation: boolean; - // If there are no instructions available (neither in the exercise problemStatement nor the legacy README.md) emits an event + // Emits an event if the instructions are not available via the problemStatement @Output() public onNoInstructionsAvailable = new EventEmitter(); @@ -94,7 +93,6 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes constructor( public viewContainerRef: ViewContainerRef, private resultService: ResultService, - private repositoryFileService: RepositoryFileService, private participationWebsocketService: ParticipationWebsocketService, private programmingExerciseTaskWrapper: ProgrammingExerciseTaskExtensionWrapper, private programmingExercisePlantUmlWrapper: ProgrammingExercisePlantUmlExtensionWrapper, @@ -155,7 +153,7 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes // If the exercise is not loaded, the instructions can't be loaded and so there is no point in loading the results, etc, yet. if (!this.isLoading && this.exercise && this.participation && (this.isInitial || participationHasChanged)) { this.isLoading = true; - return this.loadInstructions().pipe( + return of(this.exercise.problemStatement).pipe( // If no instructions can be loaded, abort pipe and hide the instruction panel tap((problemStatement) => { if (!problemStatement) { @@ -291,26 +289,6 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes ); } - /** - * Loads the instructions for the programming exercise. - * We added the problemStatement later, historically the instructions where a file in the student's repository - * This is why we now prefer the problemStatement and if it doesn't exist try to load the readme. - */ - loadInstructions(): Observable { - if (this.exercise.problemStatement) { - return of(this.exercise.problemStatement); - } else { - if (!this.participation.id) { - return of(undefined); - } - return this.repositoryFileService.get(this.participation.id, 'README.md').pipe( - catchError(() => of(undefined)), - // Old readme files contain chars instead of our domain command tags - replace them when loading the file - map((fileObj) => fileObj && fileObj.fileContent.replace(new RegExp(/✅/, 'g'), '[task]')), - ); - } - } - private renderMarkdown(): void { // Highlight differences between previous and current markdown if ( diff --git a/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts b/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts index 679c1fa41c98..e0916b34a07a 100644 --- a/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts +++ b/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts @@ -19,6 +19,7 @@ import { MockCodeEditorConflictStateService } from '../../helpers/mocks/service/ import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; import { TreeviewModule } from 'app/exercises/programming/shared/code-editor/treeview/treeview.module'; import { TreeviewItem } from 'app/exercises/programming/shared/code-editor/treeview/models/treeview-item'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; describe('CodeEditorFileBrowserComponent', () => { let comp: CodeEditorFileBrowserComponent; @@ -149,6 +150,25 @@ describe('CodeEditorFileBrowserComponent', () => { expect(renderedFiles).toHaveLength(3); }); + it('should toggle tree compression', () => { + comp.repositoryFiles = { + file1: FileType.FILE, + }; + const treeNode = { + folder: '', + file: 'file1', + children: [], + text: 'file1', + value: 'file1', + }; + jest.spyOn(comp, 'buildTree').mockReturnValue([treeNode]); + const transformTreeToTreeViewItemStub = jest.spyOn(comp, 'transformTreeToTreeViewItem').mockReturnValue([new TreeviewItem(treeNode)]); + comp.compressFolders = false; + comp.toggleTreeCompress(); + expect(comp.compressFolders).toBeTrue(); + expect(transformTreeToTreeViewItemStub).toHaveBeenCalledExactlyOnceWith([treeNode]); + }); + it('should create compressed treeviewItems with nested folder structure', () => { comp.repositoryFiles = { folder: FileType.FOLDER, @@ -205,7 +225,6 @@ describe('CodeEditorFileBrowserComponent', () => { }; const forbiddenFiles = { 'danger.bin': FileType.FILE, - 'README.md': FileType.FILE, '.hidden': FileType.FILE, '.': FileType.FOLDER, }; @@ -310,6 +329,42 @@ describe('CodeEditorFileBrowserComponent', () => { expect(renderedFiles).toHaveLength(0); }); + it('should select the correct file based on the user selection', () => { + const fileToSelect = 'folder/file1'; + const otherFile = 'folder2/file2'; + comp.repositoryFiles = { + folder: FileType.FOLDER, + 'folder/file1': FileType.FILE, + folder2: FileType.FOLDER, + 'folder/file2': FileType.FILE, + }; + comp.filesTreeViewItem = [ + new TreeviewItem({ + checked: false, + text: fileToSelect, + value: fileToSelect, + children: [], + } as any), + new TreeviewItem({ + checked: false, + text: otherFile, + value: otherFile, + children: [], + }), + ]; + comp.selectedFile = undefined; + const nodeFirstFile = comp.filesTreeViewItem[0]; + comp.handleNodeSelected(nodeFirstFile); + expect(nodeFirstFile.checked).toBeTrue(); + expect(comp.selectedFile).toBe(fileToSelect); + // Deselect the current file. + const nodeSecondFile = comp.filesTreeViewItem[1]; + comp.handleNodeSelected(nodeSecondFile); + expect(nodeFirstFile.checked).toBeFalse(); + expect(nodeSecondFile.checked).toBeTrue(); + expect(comp.selectedFile).toBe(otherFile); + }); + it('should set node to checked if its file gets selected and update ui', () => { const selectedFile = 'folder/file1'; const repositoryFiles = { @@ -505,6 +560,26 @@ describe('CodeEditorFileBrowserComponent', () => { expect(createFileStub).not.toHaveBeenCalled(); }); + it('should manage the root file/folder it is currently creating', () => { + comp.setCreatingFileInRoot(FileType.FILE); + expect(comp.creatingFile).toEqual(['', FileType.FILE]); + comp.setCreatingFileInRoot(FileType.FOLDER); + expect(comp.creatingFile).toEqual(['', FileType.FOLDER]); + comp.clearCreatingFile(); + expect(comp.creatingFile).toBeUndefined(); + }); + + it('should manage the file/folder it is currently creating within another folder', () => { + const folder = 'folder'; + const item = { value: folder } as TreeviewItem; + comp.setCreatingFile({ item, fileType: FileType.FILE }); + expect(comp.creatingFile).toEqual([folder, FileType.FILE]); + comp.setCreatingFile({ item, fileType: FileType.FOLDER }); + expect(comp.creatingFile).toEqual([folder, FileType.FOLDER]); + comp.clearCreatingFile(); + expect(comp.creatingFile).toBeUndefined(); + }); + it('should update repository file entry on rename', fakeAsync(() => { const fileName = 'file1'; const afterRename = 'newFileName'; @@ -761,6 +836,18 @@ describe('CodeEditorFileBrowserComponent', () => { expect(renamingInput).toBeNull(); })); + it('should manage the file it is currently renaming', () => { + comp.repositoryFiles = { + 'folder/file1': FileType.FILE, + folder: FileType.FOLDER, + }; + const item = { value: 'folder/file1', text: 'file1' } as TreeviewItem; + comp.setRenamingFile(item); + expect(comp.renamingFile).toEqual(['folder/file1', 'file1', FileType.FILE]); + comp.clearRenamingFile(); + expect(comp.renamingFile).toBeUndefined(); + }); + it('should disable action buttons if there is a git conflict', () => { const repositoryContent: { [fileName: string]: string } = {}; getStatusStub.mockReturnValue(of({ repositoryStatus: CommitState.CONFLICT })); @@ -806,6 +893,7 @@ describe('CodeEditorFileBrowserComponent', () => { const filteredChangeInformation = { 'Class.java': true, 'Document.md': false, + 'README.md': true, }; const getFilesWithChangeInfoStub = jest.fn().mockReturnValue(of(changeInformation)); codeEditorRepositoryFileService.getFilesWithInformationAboutChange = getFilesWithChangeInfoStub; @@ -821,6 +909,21 @@ describe('CodeEditorFileBrowserComponent', () => { loadFiles.unsubscribe(); })); + it('should open a modal when trying to delete a file', () => { + comp.repositoryFiles = { + 'folder/file1': FileType.FILE, + folder: FileType.FOLDER, + }; + const item = { value: 'folder/file1', text: 'file1' } as TreeviewItem; + const modalRef = { componentInstance: { parent: undefined, fileNameToDelete: undefined, fileType: undefined } } as NgbModalRef; + const openModalStub = jest.spyOn(comp.modalService, 'open').mockReturnValue(modalRef); + comp.openDeleteFileModal(item); + expect(openModalStub).toHaveBeenCalledOnce(); + expect(modalRef.componentInstance.parent).toBe(comp); + expect(modalRef.componentInstance.fileNameToDelete).toBe('folder/file1'); + expect(modalRef.componentInstance.fileType).toBe(FileType.FILE); + }); + describe('getFolderBadges', () => { // Mock fileBadges data const mockFileBadges = { diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts index b10b7420640a..4a4bee296170 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts @@ -1,16 +1,15 @@ -import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, flush, tick } from '@angular/core/testing'; import { TranslateService } from '@ngx-translate/core'; import { By } from '@angular/platform-browser'; -import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { NgbModal, NgbModalRef, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; -import { DebugElement } from '@angular/core'; +import { DebugElement, VERSION } from '@angular/core'; import { Theme, ThemeService } from 'app/core/theme/theme.service'; import dayjs from 'dayjs/esm'; -import { Subject, Subscription, of, throwError } from 'rxjs'; +import { Subscription, of, throwError } from 'rxjs'; import { ArtemisTestModule } from '../../test.module'; import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { MockResultService } from '../../helpers/mocks/service/mock-result.service'; -import { MockRepositoryFileService } from '../../helpers/mocks/service/mock-repository-file.service'; import { problemStatementBubbleSortNotExecutedHtml, problemStatementEmptySecondTask, @@ -28,7 +27,6 @@ import { triggerChanges } from '../../helpers/utils/general.utils'; import { LocalStorageService } from 'ngx-webstorage'; import { Participation } from 'app/entities/participation/participation.model'; import { ResultService } from 'app/exercises/shared/result/result.service'; -import { RepositoryFileService } from 'app/exercises/shared/result/repository.service'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { ProgrammingExerciseInstructionTaskStatusComponent } from 'app/exercises/programming/shared/instructions-render/task/programming-exercise-instruction-task-status.component'; import { Result } from 'app/entities/result.model'; @@ -39,25 +37,21 @@ import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.s import { MockParticipationWebsocketService } from '../../helpers/mocks/service/mock-participation-websocket.service'; import { ExerciseType } from 'app/entities/exercise.model'; import { MockTranslateService, TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; -import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { MockModule } from 'ng-mocks'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; import { SafeHtmlPipe } from 'app/shared/pipes/safe-html.pipe'; -import { VERSION } from '@angular/core'; describe('ProgrammingExerciseInstructionComponent', () => { let comp: ProgrammingExerciseInstructionComponent; let fixture: ComponentFixture; let debugElement: DebugElement; let participationWebsocketService: ParticipationWebsocketService; - let repositoryFileService: RepositoryFileService; let programmingExerciseParticipationService: ProgrammingExerciseParticipationService; let programmingExerciseGradingService: ProgrammingExerciseGradingService; let modalService: NgbModal; let themeService: ThemeService; let subscribeForLatestResultOfParticipationStub: jest.SpyInstance; - let getFileStub: jest.SpyInstance; let openModalStub: jest.SpyInstance; let getLatestResultWithFeedbacks: jest.SpyInstance; @@ -82,7 +76,6 @@ describe('ProgrammingExerciseInstructionComponent', () => { { provide: ResultService, useClass: MockResultService }, { provide: ProgrammingExerciseParticipationService, useClass: MockProgrammingExerciseParticipationService }, { provide: ParticipationWebsocketService, useClass: MockParticipationWebsocketService }, - { provide: RepositoryFileService, useClass: MockRepositoryFileService }, { provide: NgbModal, useClass: MockNgbModalService }, { provide: ProgrammingExerciseGradingService, useValue: { getTestCases: () => of() } }, ], @@ -96,13 +89,11 @@ describe('ProgrammingExerciseInstructionComponent', () => { participationWebsocketService = debugElement.injector.get(ParticipationWebsocketService); programmingExerciseParticipationService = debugElement.injector.get(ProgrammingExerciseParticipationService); programmingExerciseGradingService = debugElement.injector.get(ProgrammingExerciseGradingService); - repositoryFileService = debugElement.injector.get(RepositoryFileService); modalService = debugElement.injector.get(NgbModal); themeService = debugElement.injector.get(ThemeService); subscribeForLatestResultOfParticipationStub = jest.spyOn(participationWebsocketService, 'subscribeForLatestResultOfParticipation'); openModalStub = jest.spyOn(modalService, 'open'); - getFileStub = jest.spyOn(repositoryFileService, 'get'); getLatestResultWithFeedbacks = jest.spyOn(programmingExerciseParticipationService, 'getLatestResultWithFeedback'); comp.personalParticipation = true; @@ -113,13 +104,14 @@ describe('ProgrammingExerciseInstructionComponent', () => { jest.restoreAllMocks(); }); - it('should on participation change clear old subscription for participation results set up new one', () => { + it('should on participation change clear old subscription for participation results set up new one', fakeAsync(() => { const exercise: ProgrammingExercise = { id: 1, numberOfAssessmentsOfCorrectionRounds: [], secondCorrectionEnabled: false, studentAssignedTeamIdComputed: false, isAtLeastTutor: true, + problemStatement: 'lorem ipsum dolor sit amet', }; const oldParticipation: Participation = { id: 1 }; const result: Result = { id: 1 }; @@ -138,84 +130,11 @@ describe('ProgrammingExerciseInstructionComponent', () => { expect(subscribeForLatestResultOfParticipationStub).toHaveBeenCalledOnce(); expect(subscribeForLatestResultOfParticipationStub).toHaveBeenCalledWith(participation.id, true, exercise.id); expect(comp.participationSubscription).not.toEqual(oldSubscription); + flush(); expect(comp.isInitial).toBeTrue(); - }); - - it('should try to fetch README.md from assignment repository if no problemStatement was provided', () => { - const result: Result = { id: 1, feedbacks: [] }; - const participation: Participation = { id: 2 }; - const exercise: ProgrammingExercise = { - id: 3, - course: { id: 4 }, - numberOfAssessmentsOfCorrectionRounds: [], - secondCorrectionEnabled: false, - studentAssignedTeamIdComputed: false, - }; - const getFileSubject = new Subject<{ fileContent: string; fileName: string }>(); - const loadInitialResultStub = jest.spyOn(comp, 'loadInitialResult').mockReturnValue(of(result)); - const updateMarkdownStub = jest.spyOn(comp, 'updateMarkdown'); - getFileStub.mockReturnValue(getFileSubject); - comp.participation = participation; - comp.exercise = exercise; - comp.isInitial = true; - comp.isLoading = false; - - fixture.detectChanges(); - triggerChanges(comp); - fixture.detectChanges(); - expect(comp.isLoading).toBeTrue(); - expect(debugElement.query(By.css('#programming-exercise-instructions-loading'))).not.toBeNull(); - expect(debugElement.query(By.css('#programming-exercise-instructions-content'))).toBeNull(); - expect(getFileStub).toHaveBeenCalledOnce(); - expect(getFileStub).toHaveBeenCalledWith(participation.id, 'README.md'); - - getFileSubject.next({ fileContent: 'lorem ipsum', fileName: 'README.md' }); - expect(comp.problemStatement).toBe('lorem ipsum'); - expect(loadInitialResultStub).toHaveBeenCalledOnce(); - expect(comp.latestResult).toEqual(result); - expect(updateMarkdownStub).toHaveBeenCalledOnce(); - expect(comp.isInitial).toBeFalse(); - expect(comp.isLoading).toBeFalse(); - fixture.detectChanges(); - expect(debugElement.query(By.css('#programming-exercise-instructions-loading'))).toBeNull(); - expect(debugElement.query(By.css('#programming-exercise-instructions-content'))).not.toBeNull(); - }); - - it('should NOT try to fetch README.md from assignment repository if a problemStatement was provided', () => { - const result: Result = { id: 1, feedbacks: [] }; - const participation: Participation = { id: 2 }; - const problemstatement = 'lorem ipsum'; - const exercise: ProgrammingExercise = { - id: 3, - course: { id: 4 }, - problemStatement: problemstatement, - numberOfAssessmentsOfCorrectionRounds: [], - secondCorrectionEnabled: false, - studentAssignedTeamIdComputed: false, - }; - const loadInitialResultStub = jest.spyOn(comp, 'loadInitialResult').mockReturnValue(of(result)); - const updateMarkdownStub = jest.spyOn(comp, 'updateMarkdown'); - comp.participation = participation; - comp.exercise = exercise; - comp.isInitial = true; - comp.isLoading = false; - - fixture.detectChanges(); - triggerChanges(comp); - - expect(getFileStub).not.toHaveBeenCalled(); - expect(comp.problemStatement).toBe('lorem ipsum'); - expect(loadInitialResultStub).toHaveBeenCalledOnce(); - expect(comp.latestResult).toEqual(result); - expect(updateMarkdownStub).toHaveBeenCalledOnce(); - expect(comp.isInitial).toBeFalse(); - expect(comp.isLoading).toBeFalse(); - fixture.detectChanges(); - expect(debugElement.query(By.css('#programming-exercise-instructions-loading'))).toBeNull(); - expect(debugElement.query(By.css('#programming-exercise-instructions-content'))).not.toBeNull(); - }); + })); - it('should emit that no instructions are available if there is neither a problemStatement provided nor a README.md can be retrieved', () => { + it('should emit that no instructions are available if there is no problem statement', () => { const result: Result = { id: 1, feedbacks: [] }; const participation: Participation = { id: 2 }; const exercise: ProgrammingExercise = { @@ -225,11 +144,9 @@ describe('ProgrammingExerciseInstructionComponent', () => { secondCorrectionEnabled: false, studentAssignedTeamIdComputed: false, }; - const getFileSubject = new Subject<{ fileContent: string; fileName: string }>(); const loadInitialResultStub = jest.spyOn(comp, 'loadInitialResult').mockReturnValue(of(result)); const updateMarkdownStub = jest.spyOn(comp, 'updateMarkdown'); const noInstructionsAvailableSpy = jest.spyOn(comp.onNoInstructionsAvailable, 'emit'); - getFileStub.mockReturnValue(getFileSubject); comp.participation = participation; comp.exercise = exercise; comp.isInitial = true; @@ -237,11 +154,6 @@ describe('ProgrammingExerciseInstructionComponent', () => { fixture.detectChanges(); triggerChanges(comp); - expect(comp.isLoading).toBeTrue(); - expect(getFileStub).toHaveBeenCalledOnce(); - expect(getFileStub).toHaveBeenCalledWith(participation.id, 'README.md'); - - getFileSubject.error('fatal error'); expect(comp.problemStatement).toBeUndefined(); expect(loadInitialResultStub).not.toHaveBeenCalled(); expect(comp.latestResult).toBeUndefined(); From 0331b31641159be2eb57cc2b37a57c1e1ac46abb Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Wed, 21 Aug 2024 13:36:11 +0300 Subject: [PATCH 09/10] Development: Update server and client dependencies --- build.gradle | 26 +- gradle.properties | 7 +- gradle/wrapper/gradle-wrapper.properties | 2 +- package-lock.json | 144 ++-- package.json | 16 +- .../build.gradle | 28 +- .../endpoints.json | 1 + .../src/main/typeScript/package-lock.json | 615 ++++++++---------- .../src/main/typeScript/package.json | 11 +- 9 files changed, 404 insertions(+), 446 deletions(-) create mode 100644 supporting_scripts/analysis-of-endpoint-connections/endpoints.json diff --git a/build.gradle b/build.gradle index ae88a8170eda..8eda5b8226e5 100644 --- a/build.gradle +++ b/build.gradle @@ -322,7 +322,7 @@ dependencies { implementation "com.github.docker-java:docker-java-transport-httpclient5:${docker_java_version}" // use newest version of commons-compress to avoid security issues through outdated dependencies - implementation "org.apache.commons:commons-compress:1.27.0" + implementation "org.apache.commons:commons-compress:1.27.1" // import JHipster dependencies BOM @@ -373,8 +373,8 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-oauth2-resource-server:${spring_boot_version}" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:${spring_boot_version}" - implementation "org.springframework.ldap:spring-ldap-core:3.2.4" - implementation "org.springframework.data:spring-data-ldap:3.3.2" + implementation "org.springframework.ldap:spring-ldap-core:3.2.6" + implementation "org.springframework.data:spring-data-ldap:3.3.3" implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:4.1.3") { // NOTE: these modules contain security vulnerabilities and are not needed @@ -385,9 +385,9 @@ dependencies { implementation "org.springframework.cloud:spring-cloud-commons:4.1.4" implementation "io.netty:netty-all:4.1.112.Final" - implementation "io.projectreactor.netty:reactor-netty:1.1.21" - implementation "org.springframework:spring-messaging:6.1.11" - implementation "org.springframework.retry:spring-retry:2.0.7" + implementation "io.projectreactor.netty:reactor-netty:1.1.22" + implementation "org.springframework:spring-messaging:6.1.12" + implementation "org.springframework.retry:spring-retry:2.0.8" implementation "org.springframework.security:spring-security-config:${spring_security_version}" implementation "org.springframework.security:spring-security-data:${spring_security_version}" @@ -427,7 +427,7 @@ dependencies { implementation "org.zalando:jackson-datatype-problem:0.27.1" implementation "com.ibm.icu:icu4j-charset:75.1" implementation "com.github.seancfoley:ipaddress:5.5.0" - implementation "org.apache.maven:maven-model:3.9.8" + implementation "org.apache.maven:maven-model:3.9.9" // NOTE: 3.0.2 is broken for splitting lecture specific PDFs implementation "org.apache.pdfbox:pdfbox:3.0.1" implementation "org.apache.commons:commons-csv:1.11.0" @@ -436,7 +436,7 @@ dependencies { implementation "net.lingala.zip4j:zip4j:2.11.5" implementation "org.jgrapht:jgrapht-core:1.5.2" // use newest version of guava to avoid security issues through outdated dependencies - implementation "com.google.guava:guava:33.2.1-jre" + implementation "com.google.guava:guava:33.3.0-jre" implementation "com.sun.activation:jakarta.activation:2.0.1" // use newest version of gson to avoid security issues through outdated dependencies @@ -470,11 +470,11 @@ dependencies { testImplementation "org.assertj:assertj-core:3.26.3" testImplementation "org.mockito:mockito-core:${mockito_version}" testImplementation "org.mockito:mockito-junit-jupiter:${mockito_version}" - testImplementation "io.github.classgraph:classgraph:4.8.174" + testImplementation "io.github.classgraph:classgraph:4.8.175" testImplementation "org.awaitility:awaitility:4.2.2" testImplementation "org.apache.maven.shared:maven-invoker:3.3.0" - testImplementation "org.gradle:gradle-tooling-api:8.9" - testImplementation "org.apache.maven.surefire:surefire-report-parser:3.3.1" + testImplementation "org.gradle:gradle-tooling-api:8.10" + testImplementation "org.apache.maven.surefire:surefire-report-parser:3.4.0" testImplementation "com.opencsv:opencsv:5.9" testImplementation("io.zonky.test:embedded-database-spring-test:2.5.1") { exclude group: "org.testcontainers", module: "mariadb" @@ -486,7 +486,7 @@ dependencies { } testImplementation("net.bytebuddy:byte-buddy") { version { - strictly "1.14.18" + strictly "1.14.19" } } // cannot update due to "Syntax error in SQL statement "WITH ids_to_delete" @@ -558,7 +558,7 @@ tasks.withType(Test).configureEach { } wrapper { - gradleVersion = "8.9" + gradleVersion = "8.10" } tasks.register("stage") { diff --git a/gradle.properties b/gradle.properties index db7d546da641..cfff6f39ed14 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ npm_version=10.7.0 # Dependency versions jhipster_dependencies_version=8.6.0 spring_boot_version=3.3.2 -spring_security_version=6.3.1 +spring_security_version=6.3.2 # TODO: before we upgrade to 6.5.x, we need to make sure that there are no performance issues with empty sets or lists hibernate_version=6.4.9.Final # TODO: can we update to 5.x? @@ -25,10 +25,11 @@ sshd_version=2.13.2 checkstyle_version=10.17.0 jplag_version=5.1.0 slf4j_version=2.0.16 -sentry_version=7.13.0 +sentry_version=7.14.0 liquibase_version=4.29.1 docker_java_version=3.4.0 -logback_version=1.5.6 +logback_version=1.5.7 +java_parser_version=3.26.1 # gradle plugin version gradle_node_plugin_version=7.0.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e5490..9355b4155759 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/package-lock.json b/package-lock.json index 4e2059590f91..bc5fa5d014c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,13 +38,13 @@ "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", - "ace-builds": "1.35.4", + "ace-builds": "1.35.5", "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", - "core-js": "3.38.0", + "core-js": "3.38.1", "crypto-js": "4.2.0", - "dayjs": "1.11.12", + "dayjs": "1.11.13", "diff-match-patch-typescript": "1.0.8", "dompurify": "3.1.6", "export-to-csv": "1.3.0", @@ -61,7 +61,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.155.4", + "posthog-js": "1.157.2", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -94,14 +94,14 @@ "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.3.0", + "@types/node": "22.4.2", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", "@types/sockjs-client": "1.5.4", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.1.0", - "@typescript-eslint/parser": "8.1.0", + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", "eslint": "9.9.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", @@ -109,7 +109,7 @@ "eslint-plugin-jest-extended": "2.4.0", "eslint-plugin-prettier": "5.2.1", "folder-hash": "4.0.4", - "husky": "9.1.4", + "husky": "9.1.5", "jest": "29.7.0", "jest-canvas-mock": "2.5.2", "jest-date-mock": "1.0.10", @@ -6398,13 +6398,13 @@ } }, "node_modules/@types/node": { - "version": "22.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.3.0.tgz", - "integrity": "sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==", + "version": "22.4.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.2.tgz", + "integrity": "sha512-nAvM3Ey230/XzxtyDcJ+VjvlzpzoHwLsF7JaDRfoI0ytO0mVheerNmM45CtA0yOILXwXXxOrcUWH3wltX+7PSw==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.18.2" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-forge": { @@ -6604,17 +6604,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.1.0.tgz", - "integrity": "sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/type-utils": "8.1.0", - "@typescript-eslint/utils": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -6638,16 +6638,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.1.0.tgz", - "integrity": "sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { @@ -6667,14 +6667,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.1.0.tgz", - "integrity": "sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6685,14 +6685,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.1.0.tgz", - "integrity": "sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/utils": "8.1.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6710,9 +6710,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.1.0.tgz", - "integrity": "sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, "license": "MIT", "engines": { @@ -6724,14 +6724,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.1.0.tgz", - "integrity": "sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6753,16 +6753,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.1.0.tgz", - "integrity": "sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0" + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6776,13 +6776,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.1.0.tgz", - "integrity": "sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", + "@typescript-eslint/types": "8.2.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -7019,9 +7019,9 @@ } }, "node_modules/ace-builds": { - "version": "1.35.4", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.35.4.tgz", - "integrity": "sha512-r0KQclhZ/uk5a4zOqRYQkJuQuu4vFMiA6VTj54Tk4nI1TUR3iEMMppZkWbNoWEgWwv4ciDloObb9Rf4V55Qgjw==", + "version": "1.35.5", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.35.5.tgz", + "integrity": "sha512-yh3V5BLHlN6gwbmk5sV00WRRvdEggJGJ3AIHhOOGHlgDWNWCSvOnHPO7Chb+AqaxxHuvpxOdXd7ZQesaiuJQZQ==", "license": "BSD-3-Clause" }, "node_modules/acorn": { @@ -8643,9 +8643,9 @@ } }, "node_modules/core-js": { - "version": "3.38.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.0.tgz", - "integrity": "sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -9350,9 +9350,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.12", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", - "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==", + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "license": "MIT" }, "node_modules/debug": { @@ -11777,9 +11777,9 @@ } }, "node_modules/husky": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", - "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", + "integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==", "dev": true, "license": "MIT", "bin": { @@ -17363,9 +17363,9 @@ "license": "MIT" }, "node_modules/posthog-js": { - "version": "1.155.4", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.155.4.tgz", - "integrity": "sha512-suxwAsmZGqMDXJe/RaCKI3PaDEHiuMDDhKcJklgGAg7eDnywieRkr5CoPcOOvnqTDMnuOPETr98jpYBXKUwGFQ==", + "version": "1.157.2", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.157.2.tgz", + "integrity": "sha512-ATYKGs+Q51u26nHHhrhWNh1whqFm7j/rwQQYw+y6/YzNmRlo+YsqrGZji9nqXb9/4fo0ModDr+ZmuOI3hKkUXA==", "license": "MIT", "dependencies": { "fflate": "^0.4.8", @@ -20089,9 +20089,9 @@ } }, "node_modules/undici-types": { - "version": "6.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.18.2.tgz", - "integrity": "sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index d48bfbed97b5..1eda30265f5f 100644 --- a/package.json +++ b/package.json @@ -41,13 +41,13 @@ "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", - "ace-builds": "1.35.4", + "ace-builds": "1.35.5", "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", - "core-js": "3.38.0", + "core-js": "3.38.1", "crypto-js": "4.2.0", - "dayjs": "1.11.12", + "dayjs": "1.11.13", "diff-match-patch-typescript": "1.0.8", "dompurify": "3.1.6", "export-to-csv": "1.3.0", @@ -64,7 +64,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.155.4", + "posthog-js": "1.157.2", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -132,14 +132,14 @@ "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.3.0", + "@types/node": "22.4.2", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", "@types/sockjs-client": "1.5.4", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.1.0", - "@typescript-eslint/parser": "8.1.0", + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", "eslint": "9.9.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", @@ -147,7 +147,7 @@ "eslint-plugin-jest-extended": "2.4.0", "eslint-plugin-prettier": "5.2.1", "folder-hash": "4.0.4", - "husky": "9.1.4", + "husky": "9.1.5", "jest": "29.7.0", "jest-canvas-mock": "2.5.2", "jest-date-mock": "1.0.10", diff --git a/supporting_scripts/analysis-of-endpoint-connections/build.gradle b/supporting_scripts/analysis-of-endpoint-connections/build.gradle index 0e41c785d65c..226588714dd0 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/build.gradle +++ b/supporting_scripts/analysis-of-endpoint-connections/build.gradle @@ -1,38 +1,38 @@ plugins { - id 'java' - id 'application' + id "java" + id "application" } -group 'de.tum.in.www1.artemis' -version '1.0-SNAPSHOT' +group "de.tum.in.www1.artemis" +version "1.0.0" repositories { mavenCentral() } -evaluationDependsOn(':') +evaluationDependsOn(":") dependencies { - implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.26.0' - implementation 'com.github.javaparser:javaparser-core:3.26.0' - implementation 'com.github.javaparser:javaparser-core-serialization:3.26.0' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0' + implementation "com.github.javaparser:javaparser-symbol-solver-core:${project.java_parser_version}" + implementation "com.github.javaparser:javaparser-core:${project.java_parser_version}" + implementation "com.github.javaparser:javaparser-core-serialization:${project.java_parser_version}" + implementation "com.fasterxml.jackson.core:jackson-databind:${project.fasterxml_version}" implementation rootProject.ext.springBootStarterWeb - implementation 'org.slf4j:slf4j-api:1.7.32' - implementation 'ch.qos.logback:logback-classic:1.2.6' + implementation "org.slf4j:slf4j-api:${project.slf4j_version}" + implementation "ch.qos.logback:logback-classic:${project.logback_version}" } task runEndpointParser(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath - mainClass = 'de.tum.cit.endpointanalysis.EndpointParser' + mainClass = "de.tum.cit.endpointanalysis.EndpointParser" } task runEndpointAnalysis(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath - mainClass = 'de.tum.cit.endpointanalysis.EndpointAnalyzer' + mainClass = "de.tum.cit.endpointanalysis.EndpointAnalyzer" } task runRestCallAnalysis(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath - mainClass = 'de.tum.cit.endpointanalysis.RestCallAnalyzer' + mainClass = "de.tum.cit.endpointanalysis.RestCallAnalyzer" } diff --git a/supporting_scripts/analysis-of-endpoint-connections/endpoints.json b/supporting_scripts/analysis-of-endpoint-connections/endpoints.json new file mode 100644 index 000000000000..7846fb272dbc --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/endpoints.json @@ -0,0 +1 @@ +[{"filePath":"CourseCompetencyResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getCompetencyTitle","httpMethodAnnotation":"GetMapping","URI":"\"course-competencies/{competencyId}/title\"","className":"CourseCompetencyResource","line":115,"otherAnnotations":["@GetMapping(\"course-competencies/{competencyId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCompetencyTitles","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/titles\"","className":"CourseCompetencyResource","line":128,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/titles\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCompetency","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}\"","className":"CourseCompetencyResource","line":143,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCompetenciesWithProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies\"","className":"CourseCompetencyResource","line":163,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyStudentProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/student-progress\"","className":"CourseCompetencyResource","line":180,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}/student-progress\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyCourseProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/course-progress\"","className":"CourseCompetencyResource","line":208,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}/course-progress\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetenciesForImport","httpMethodAnnotation":"GetMapping","URI":"\"course-competencies/for-import\"","className":"CourseCompetencyResource","line":226,"otherAnnotations":["@GetMapping(\"course-competencies/for-import\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importAllCompetenciesFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/course-competencies/import-all/{sourceCourseId}\"","className":"CourseCompetencyResource","line":242,"otherAnnotations":["@PostMapping(\"courses/{courseId}/course-competencies/import-all/{sourceCourseId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyRelations","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/relations\"","className":"CourseCompetencyResource","line":276,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/relations\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createCompetencyRelation","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/course-competencies/relations\"","className":"CourseCompetencyResource","line":294,"otherAnnotations":["@PostMapping(\"courses/{courseId}/course-competencies/relations\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"removeCompetencyRelation","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/course-competencies/relations/{competencyRelationId}\"","className":"CourseCompetencyResource","line":319,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/course-competencies/relations/{competencyRelationId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"generateCompetenciesFromCourseDescription","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/course-competencies/generate-from-description\"","className":"CourseCompetencyResource","line":342,"otherAnnotations":["@PostMapping(\"courses/{courseId}/course-competencies/generate-from-description\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"setJudgementOfLearning","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/jol/{jolValue}\"","className":"CourseCompetencyResource","line":364,"otherAnnotations":["@PutMapping(\"courses/{courseId}/course-competencies/{competencyId}/jol/{jolValue}\")","@FeatureToggle(Feature.StudentCourseAnalyticsDashboard)","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLatestJudgementOfLearningForCompetency","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/jol\"","className":"CourseCompetencyResource","line":384,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}/jol\")","@FeatureToggle(Feature.StudentCourseAnalyticsDashboard)","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLatestJudgementOfLearningForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/jol\"","className":"CourseCompetencyResource","line":403,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/jol\")","@FeatureToggle(Feature.StudentCourseAnalyticsDashboard)","@EnforceAtLeastStudentInCourse"]}]},{"filePath":"PrerequisiteResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getPrerequisitesWithProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/prerequisites\"","className":"PrerequisiteResource","line":99,"otherAnnotations":["@GetMapping(\"courses/{courseId}/prerequisites\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getPrerequisite","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/prerequisites/{prerequisiteId}\"","className":"PrerequisiteResource","line":116,"otherAnnotations":["@GetMapping(\"courses/{courseId}/prerequisites/{prerequisiteId}\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createPrerequisite","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites\"","className":"PrerequisiteResource","line":138,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createPrerequisite","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/bulk\"","className":"PrerequisiteResource","line":160,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/bulk\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importPrerequisite","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import\"","className":"PrerequisiteResource","line":184,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importPrerequisites","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import/bulk\"","className":"PrerequisiteResource","line":211,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import/bulk\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importAllPrerequisitesFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import-all/{sourceCourseId}\"","className":"PrerequisiteResource","line":249,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import-all/{sourceCourseId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importStandardizedPrerequisites","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import-standardized\"","className":"PrerequisiteResource","line":283,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import-standardized\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"updatePrerequisite","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/prerequisites\"","className":"PrerequisiteResource","line":302,"otherAnnotations":["@PutMapping(\"courses/{courseId}/prerequisites\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"deletePrerequisite","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/prerequisites/{prerequisiteId}\"","className":"PrerequisiteResource","line":326,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/prerequisites/{prerequisiteId}\")","@EnforceAtLeastInstructorInCourse"]}]},{"filePath":"StandardizedCompetencyResource","classRequestMapping":"\"api/standardized-competencies/\"","endpoints":[{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getStandardizedCompetency","httpMethodAnnotation":"GetMapping","URI":"\"{competencyId}\"","className":"StandardizedCompetencyResource","line":60,"otherAnnotations":["@GetMapping(\"{competencyId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getAllForTreeView","httpMethodAnnotation":"GetMapping","URI":"\"for-tree-view\"","className":"StandardizedCompetencyResource","line":76,"otherAnnotations":["@GetMapping(\"for-tree-view\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getKnowledgeArea","httpMethodAnnotation":"GetMapping","URI":"\"knowledge-areas/{knowledgeAreaId}\"","className":"StandardizedCompetencyResource","line":93,"otherAnnotations":["@GetMapping(\"knowledge-areas/{knowledgeAreaId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getSources","httpMethodAnnotation":"GetMapping","URI":"\"sources\"","className":"StandardizedCompetencyResource","line":109,"otherAnnotations":["@GetMapping(\"sources\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]}]},{"filePath":"CompetencyResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getCompetenciesWithProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/competencies\"","className":"CompetencyResource","line":96,"otherAnnotations":["@GetMapping(\"courses/{courseId}/competencies\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetency","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/competencies/{competencyId}\"","className":"CompetencyResource","line":113,"otherAnnotations":["@GetMapping(\"courses/{courseId}/competencies/{competencyId}\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createCompetency","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies\"","className":"CompetencyResource","line":135,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createCompetencies","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/bulk\"","className":"CompetencyResource","line":157,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/bulk\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importCompetency","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import\"","className":"CompetencyResource","line":181,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importCompetencies","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import/bulk\"","className":"CompetencyResource","line":208,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import/bulk\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importAllCompetenciesFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import-all/{sourceCourseId}\"","className":"CompetencyResource","line":246,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import-all/{sourceCourseId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importStandardizedCompetencies","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import-standardized\"","className":"CompetencyResource","line":280,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import-standardized\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"updateCompetency","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/competencies\"","className":"CompetencyResource","line":299,"otherAnnotations":["@PutMapping(\"courses/{courseId}/competencies\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"deleteCompetency","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/competencies/{competencyId}\"","className":"CompetencyResource","line":323,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/competencies/{competencyId}\")","@EnforceAtLeastInstructorInCourse"]}]},{"filePath":"TextUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTextUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/text-units/{textUnitId}\"","className":"TextUnitResource","line":64,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/text-units/{textUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateTextUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/text-units\"","className":"TextUnitResource","line":87,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/text-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createTextUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/text-units\"","className":"TextUnitResource","line":119,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/text-units\")","@EnforceAtLeastEditor"]}]},{"filePath":"VideoUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getVideoUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/video-units/{videoUnitId}\"","className":"VideoUnitResource","line":69,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/video-units/{videoUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateVideoUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/video-units\"","className":"VideoUnitResource","line":86,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/video-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createVideoUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/video-units\"","className":"VideoUnitResource","line":115,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/video-units\")","@EnforceAtLeastEditor"]}]},{"filePath":"ExerciseUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExerciseUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/exercise-units\"","className":"ExerciseUnitResource","line":60,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/exercise-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExerciseUnitsOfLecture","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/exercise-units\"","className":"ExerciseUnitResource","line":90,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/exercise-units\")","@EnforceAtLeastEditor"]}]},{"filePath":"AttachmentUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachment-units/{attachmentUnitId}\"","className":"AttachmentUnitResource","line":99,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachment-units/{attachmentUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateAttachmentUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/attachment-units/{attachmentUnitId}\"","className":"AttachmentUnitResource","line":122,"otherAnnotations":["@PutMapping(value = \"lectures/{lectureId}/attachment-units/{attachmentUnitId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createAttachmentUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/attachment-units\"","className":"AttachmentUnitResource","line":152,"otherAnnotations":["@PostMapping(value = \"lectures/{lectureId}/attachment-units\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"uploadSlidesForProcessing","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/attachment-units/upload\"","className":"AttachmentUnitResource","line":188,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/attachment-units/upload\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createAttachmentUnits","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/attachment-units/split/{filename}\"","className":"AttachmentUnitResource","line":217,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/attachment-units/split/{filename}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnitsData","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachment-units/data/{filename}\"","className":"AttachmentUnitResource","line":247,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachment-units/data/{filename}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getSlidesToRemove","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachment-units/slides-to-remove/{filename}\"","className":"AttachmentUnitResource","line":275,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachment-units/slides-to-remove/{filename}\")","@EnforceAtLeastEditor"]}]},{"filePath":"OnlineUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOnlineUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/online-units/{onlineUnitId}\"","className":"OnlineUnitResource","line":79,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/online-units/{onlineUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateOnlineUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/online-units\"","className":"OnlineUnitResource","line":96,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/online-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createOnlineUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/online-units\"","className":"OnlineUnitResource","line":126,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/online-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getOnlineResource","httpMethodAnnotation":"GetMapping","URI":"\"lectures/online-units/fetch-online-resource\"","className":"OnlineUnitResource","line":161,"otherAnnotations":["@GetMapping(\"lectures/online-units/fetch-online-resource\")","@EnforceAtLeastEditor"]}]},{"filePath":"LectureUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateLectureUnitsOrder","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/lecture-units-order\"","className":"LectureUnitResource","line":85,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/lecture-units-order\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"completeLectureUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/lecture-units/{lectureUnitId}/completion\"","className":"LectureUnitResource","line":123,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/lecture-units/{lectureUnitId}/completion\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteLectureUnit","httpMethodAnnotation":"DeleteMapping","URI":"\"lectures/{lectureId}/lecture-units/{lectureUnitId}\"","className":"LectureUnitResource","line":157,"otherAnnotations":["@DeleteMapping(\"lectures/{lectureId}/lecture-units/{lectureUnitId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLectureUnitForLearningPathNodeDetails","httpMethodAnnotation":"GetMapping","URI":"\"lecture-units/{lectureUnitId}/for-learning-path-node-details\"","className":"LectureUnitResource","line":186,"otherAnnotations":["@GetMapping(\"lecture-units/{lectureUnitId}/for-learning-path-node-details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLectureUnitById","httpMethodAnnotation":"GetMapping","URI":"\"lecture-units/{lectureUnitId}\"","className":"LectureUnitResource","line":201,"otherAnnotations":["@GetMapping(\"lecture-units/{lectureUnitId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"AttachmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createAttachment","httpMethodAnnotation":"PostMapping","URI":"\"attachments\"","className":"AttachmentResource","line":88,"otherAnnotations":["@PostMapping(value = \"attachments\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateAttachment","httpMethodAnnotation":"PutMapping","URI":"\"attachments/{attachmentId}\"","className":"AttachmentResource","line":113,"otherAnnotations":["@PutMapping(value = \"attachments/{attachmentId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAttachment","httpMethodAnnotation":"GetMapping","URI":"\"attachments/{id}\"","className":"AttachmentResource","line":147,"otherAnnotations":["@GetMapping(\"attachments/{id}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentsForLecture","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachments\"","className":"AttachmentResource","line":161,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachments\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAttachment","httpMethodAnnotation":"DeleteMapping","URI":"\"attachments/{attachmentId}\"","className":"AttachmentResource","line":174,"otherAnnotations":["@DeleteMapping(\"attachments/{attachmentId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"QuizPoolResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateQuizPool","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/quiz-pools\"","className":"QuizPoolResource","line":65,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/quiz-pools\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getQuizPool","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/quiz-pools\"","className":"QuizPoolResource","line":83,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/quiz-pools\")","@EnforceAtLeastInstructor"]}]},{"filePath":"AeolusTemplateResource","classRequestMapping":"\"api/aeolus/\"","endpoints":[{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplate","httpMethodAnnotation":"GetMapping","URI":"\"templates/{language}/{projectType}\"","className":"AeolusTemplateResource","line":67,"otherAnnotations":["@GetMapping({ \"templates/{language}/{projectType}\", \"templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplate","httpMethodAnnotation":"GetMapping","URI":"\"templates/{language}\"","className":"AeolusTemplateResource","line":67,"otherAnnotations":["@GetMapping({ \"templates/{language}/{projectType}\", \"templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplateScript","httpMethodAnnotation":"GetMapping","URI":"\"templateScripts/{language}/{projectType}\"","className":"AeolusTemplateResource","line":94,"otherAnnotations":["@GetMapping({ \"templateScripts/{language}/{projectType}\", \"templateScripts/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplateScript","httpMethodAnnotation":"GetMapping","URI":"\"templateScripts/{language}\"","className":"AeolusTemplateResource","line":94,"otherAnnotations":["@GetMapping({ \"templateScripts/{language}/{projectType}\", \"templateScripts/{language}\" })","@EnforceAtLeastEditor"]}]},{"filePath":"ConsistencyCheckResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"checkConsistencyOfProgrammingExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{programmingExerciseId}/consistency-check\"","className":"ConsistencyCheckResource","line":52,"otherAnnotations":["@GetMapping(\"programming-exercises/{programmingExerciseId}/consistency-check\")","@EnforceAtLeastEditor"]}]},{"filePath":"PlagiarismPostResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createPost","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/posts\"","className":"PlagiarismPostResource","line":67,"otherAnnotations":["@PostMapping(\"courses/{courseId}/posts\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updatePost","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/posts/{postId}\"","className":"PlagiarismPostResource","line":86,"otherAnnotations":["@PutMapping(\"courses/{courseId}/posts/{postId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPostsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/posts\"","className":"PlagiarismPostResource","line":103,"otherAnnotations":["@GetMapping(\"courses/{courseId}/posts\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deletePost","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/posts/{postId}\"","className":"PlagiarismPostResource","line":127,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/posts/{postId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"PlagiarismCaseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCasesForCourseForInstructor","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases/for-instructor\"","className":"PlagiarismCaseResource","line":77,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases/for-instructor\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCasesForExamForInstructor","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/plagiarism-cases/for-instructor\"","className":"PlagiarismCaseResource","line":96,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/plagiarism-cases/for-instructor\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCaseForInstructor","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-instructor\"","className":"PlagiarismCaseResource","line":121,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-instructor\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfPlagiarismCasesForExercise","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/plagiarism-cases-count\"","className":"PlagiarismCaseResource","line":149,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/plagiarism-cases-count\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"savePlagiarismCaseVerdict","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/verdict\"","className":"PlagiarismCaseResource","line":168,"otherAnnotations":["@PutMapping(\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/verdict\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCaseForExerciseForStudent","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/plagiarism-case\"","className":"PlagiarismCaseResource","line":188,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/plagiarism-case\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCasesForExercisesForStudent","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases\"","className":"PlagiarismCaseResource","line":206,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCaseForStudent","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-student\"","className":"PlagiarismCaseResource","line":254,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-student\")","@EnforceAtLeastStudent"]}]},{"filePath":"PlagiarismResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updatePlagiarismComparisonStatus","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/status\"","className":"PlagiarismResource","line":89,"otherAnnotations":["@PutMapping(\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/status\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismComparisonForSplitView","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/for-split-view\"","className":"PlagiarismResource","line":122,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/for-split-view\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deletePlagiarismComparisons","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/plagiarism-results/{plagiarismResultId}/plagiarism-comparisons\"","className":"PlagiarismResource","line":185,"otherAnnotations":["@DeleteMapping(\"exercises/{exerciseId}/plagiarism-results/{plagiarismResultId}/plagiarism-comparisons\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfPotentialPlagiarismCasesForExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/potential-plagiarism-count\"","className":"PlagiarismResource","line":213,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/potential-plagiarism-count\")","@EnforceAtLeastInstructor"]}]},{"filePath":"PlagiarismAnswerPostResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createAnswerPost","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/answer-posts\"","className":"PlagiarismAnswerPostResource","line":50,"otherAnnotations":["@PostMapping(\"courses/{courseId}/answer-posts\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateAnswerPost","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/answer-posts/{answerPostId}\"","className":"PlagiarismAnswerPostResource","line":69,"otherAnnotations":["@PutMapping(\"courses/{courseId}/answer-posts/{answerPostId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteAnswerPost","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/answer-posts/{answerPostId}\"","className":"PlagiarismAnswerPostResource","line":87,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/answer-posts/{answerPostId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"SubmissionPolicyResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getSubmissionPolicyOfExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":78,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"addSubmissionPolicyToProgrammingExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":104,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeSubmissionPolicyFromProgrammingExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":144,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"toggleSubmissionPolicy","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":179,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateSubmissionPolicy","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":227,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationSubmissionCount","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/submission-count\"","className":"SubmissionPolicyResource","line":259,"otherAnnotations":["@GetMapping(\"participations/{participationId}/submission-count\")","@EnforceAtLeastStudent"]}]},{"filePath":"PushNotificationResource","classRequestMapping":"\"api/push_notification/\"","endpoints":[{"requestMapping":"\"api/push_notification/\"","endpoint":"register","httpMethodAnnotation":"PostMapping","URI":"\"register\"","className":"PushNotificationResource","line":78,"otherAnnotations":["@PostMapping(\"register\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/push_notification/\"","endpoint":"unregister","httpMethodAnnotation":"DeleteMapping","URI":"\"unregister\"","className":"PushNotificationResource","line":117,"otherAnnotations":["@DeleteMapping(\"unregister\")","@EnforceAtLeastStudent"]}]},{"filePath":"ComplaintResponseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"lockComplaint","httpMethodAnnotation":"PostMapping","URI":"\"complaints/{complaintId}/response\"","className":"ComplaintResponseResource","line":62,"otherAnnotations":["@PostMapping(\"complaints/{complaintId}/response\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"removeLockFromComplaint","httpMethodAnnotation":"DeleteMapping","URI":"\"complaints/{complaintId}/response\"","className":"ComplaintResponseResource","line":79,"otherAnnotations":["@DeleteMapping(\"complaints/{complaintId}/response\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"refreshLockOrResolveComplaint","httpMethodAnnotation":"PatchMapping","URI":"\"complaints/{complaintId}/response\"","className":"ComplaintResponseResource","line":96,"otherAnnotations":["@PatchMapping(\"complaints/{complaintId}/response\")","@EnforceAtLeastTutor"]}]},{"filePath":"RepositoryProgrammingExerciseParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getFiles","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files\"","className":"RepositoryProgrammingExerciseParticipationResource","line":186,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}/files\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesForPlagiarismView","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files-plagiarism-view\"","className":"RepositoryProgrammingExerciseParticipationResource","line":199,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/files-plagiarism-view\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesAtCommit","httpMethodAnnotation":"GetMapping","URI":"\"repository-files-content/{commitId}\"","className":"RepositoryProgrammingExerciseParticipationResource","line":220,"otherAnnotations":["@GetMapping(value = \"repository-files-content/{commitId}\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesWithInformationAboutChange","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files-change\"","className":"RepositoryProgrammingExerciseParticipationResource","line":240,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/files-change\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFile","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":254,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}/file\", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFileForPlagiarismView","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/file-plagiarism-view\"","className":"RepositoryProgrammingExerciseParticipationResource","line":268,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/file-plagiarism-view\", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesWithContent","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files-content\"","className":"RepositoryProgrammingExerciseParticipationResource","line":287,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/files-content\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFileNames","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/file-names\"","className":"RepositoryProgrammingExerciseParticipationResource","line":303,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/file-names\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"createFile","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":315,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createFolder","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/folder\"","className":"RepositoryProgrammingExerciseParticipationResource","line":323,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/folder\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"renameFile","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/rename-file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":331,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/rename-file\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteFile","httpMethodAnnotation":"DeleteMapping","URI":"\"repository/{participationId}/file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":339,"otherAnnotations":["@Override","@DeleteMapping(value = \"repository/{participationId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"pullChanges","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/pull\"","className":"RepositoryProgrammingExerciseParticipationResource","line":346,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}/pull\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateParticipationFiles","httpMethodAnnotation":"PutMapping","URI":"\"repository/{participationId}/files\"","className":"RepositoryProgrammingExerciseParticipationResource","line":361,"otherAnnotations":["@PutMapping(\"repository/{participationId}/files\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"commitChanges","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/commit\"","className":"RepositoryProgrammingExerciseParticipationResource","line":406,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/commit\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"resetToLastCommit","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/reset\"","className":"RepositoryProgrammingExerciseParticipationResource","line":414,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/reset\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStatus","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}\"","className":"RepositoryProgrammingExerciseParticipationResource","line":422,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getBuildLogs","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/buildlogs\"","className":"RepositoryProgrammingExerciseParticipationResource","line":438,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/buildlogs\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]}]},{"filePath":"TestRepositoryResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getFiles","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}/files\"","className":"TestRepositoryResource","line":99,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}/files\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFile","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}/file\"","className":"TestRepositoryResource","line":106,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}/file\", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"createFile","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/file\"","className":"TestRepositoryResource","line":113,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"createFolder","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/folder\"","className":"TestRepositoryResource","line":121,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/folder\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"renameFile","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/rename-file\"","className":"TestRepositoryResource","line":129,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/rename-file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"deleteFile","httpMethodAnnotation":"DeleteMapping","URI":"\"test-repository/{exerciseId}/file\"","className":"TestRepositoryResource","line":137,"otherAnnotations":["@Override","@DeleteMapping(value = \"test-repository/{exerciseId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"pullChanges","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}/pull\"","className":"TestRepositoryResource","line":145,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}/pull\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"commitChanges","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/commit\"","className":"TestRepositoryResource","line":152,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/commit\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"resetToLastCommit","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/reset\"","className":"TestRepositoryResource","line":160,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/reset\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getStatus","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}\"","className":"TestRepositoryResource","line":168,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTestFiles","httpMethodAnnotation":"PutMapping","URI":"\"test-repository/{exerciseId}/files\"","className":"TestRepositoryResource","line":184,"otherAnnotations":["@PutMapping(\"test-repository/{exerciseId}/files\")","@EnforceAtLeastTutor"]}]},{"filePath":"NotificationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllNotificationsForCurrentUserFilteredBySettings","httpMethodAnnotation":"GetMapping","URI":"\"notifications\"","className":"NotificationResource","line":74,"otherAnnotations":["@GetMapping(\"notifications\")","@EnforceAtLeastStudent"]}]},{"filePath":"FileResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveMarkdownFile","httpMethodAnnotation":"PostMapping","URI":"\"markdown-file-upload\"","className":"FileResource","line":151,"otherAnnotations":["@PostMapping(\"markdown-file-upload\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getMarkdownFile","httpMethodAnnotation":"GetMapping","URI":"\"files/markdown/{filename}\"","className":"FileResource","line":170,"otherAnnotations":["@GetMapping(\"files/markdown/{filename}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTemplateFile","httpMethodAnnotation":"GetMapping","URI":"\"files/templates/{language}/{projectType}\"","className":"FileResource","line":188,"otherAnnotations":["@GetMapping({ \"files/templates/{language}/{projectType}\", \"files/templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getTemplateFile","httpMethodAnnotation":"GetMapping","URI":"\"files/templates/{language}\"","className":"FileResource","line":188,"otherAnnotations":["@GetMapping({ \"files/templates/{language}/{projectType}\", \"files/templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getDragAndDropBackgroundFile","httpMethodAnnotation":"GetMapping","URI":"\"files/drag-and-drop/backgrounds/{questionId}/*\"","className":"FileResource","line":224,"otherAnnotations":["@GetMapping(\"files/drag-and-drop/backgrounds/{questionId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getDragItemFile","httpMethodAnnotation":"GetMapping","URI":"\"files/drag-and-drop/drag-items/{dragItemId}/*\"","className":"FileResource","line":240,"otherAnnotations":["@GetMapping(\"files/drag-and-drop/drag-items/{dragItemId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadSubmission","httpMethodAnnotation":"GetMapping","URI":"\"files/file-upload-exercises/{exerciseId}/submissions/{submissionId}/*\"","className":"FileResource","line":260,"otherAnnotations":["@GetMapping(\"files/file-upload-exercises/{exerciseId}/submissions/{submissionId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseIcon","httpMethodAnnotation":"GetMapping","URI":"\"files/course/icons/{courseId}/*\"","className":"FileResource","line":293,"otherAnnotations":["@GetMapping(\"files/course/icons/{courseId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCodeOfConduct","httpMethodAnnotation":"GetMapping","URI":"\"files/templates/code-of-conduct\"","className":"FileResource","line":307,"otherAnnotations":["@GetMapping(\"files/templates/code-of-conduct\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getUserSignature","httpMethodAnnotation":"GetMapping","URI":"\"files/exam-user/signatures/{examUserId}/*\"","className":"FileResource","line":322,"otherAnnotations":["@GetMapping(\"files/exam-user/signatures/{examUserId}/*\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExamUserImage","httpMethodAnnotation":"GetMapping","URI":"\"files/exam-user/{examUserId}/*\"","className":"FileResource","line":338,"otherAnnotations":["@GetMapping(\"files/exam-user/{examUserId}/*\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLectureAttachment","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/lecture/{lectureId}/{filename}\"","className":"FileResource","line":355,"otherAnnotations":["@GetMapping(\"files/attachments/lecture/{lectureId}/{filename}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLecturePdfAttachmentsMerged","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/lecture/{lectureId}/merge-pdf\"","className":"FileResource","line":383,"otherAnnotations":["@GetMapping(\"files/attachments/lecture/{lectureId}/merge-pdf\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnitAttachment","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/attachment-unit/{attachmentUnitId}/*\"","className":"FileResource","line":415,"otherAnnotations":["@GetMapping(\"files/attachments/attachment-unit/{attachmentUnitId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnitAttachmentSlide","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/attachment-unit/{attachmentUnitId}/slide/{slideNumber}\"","className":"FileResource","line":438,"otherAnnotations":["@GetMapping(\"files/attachments/attachment-unit/{attachmentUnitId}/slide/{slideNumber}\")","@EnforceAtLeastStudent"]}]},{"filePath":"AndroidAppSiteAssociationResource","classRequestMapping":"\".well-known/\"","endpoints":[{"requestMapping":"\".well-known/\"","endpoint":"getAndroidAssetLinks","httpMethodAnnotation":"GetMapping","URI":"\"assetlinks.json\"","className":"AndroidAppSiteAssociationResource","line":40,"otherAnnotations":["@GetMapping(\"assetlinks.json\")","@ManualConfig"]}]},{"filePath":"LinkPreviewResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getLinkPreview","httpMethodAnnotation":"PostMapping","URI":"\"link-preview\"","className":"LinkPreviewResource","line":40,"otherAnnotations":["@PostMapping(\"link-preview\")","@EnforceAtLeastStudent","@Cacheable(value = \"linkPreview\", key = \"#url\", unless = \"#result == null\")"]}]},{"filePath":"AccountResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveAccount","httpMethodAnnotation":"PutMapping","URI":"\"account\"","className":"AccountResource","line":60,"otherAnnotations":["@PutMapping(\"account\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"changePassword","httpMethodAnnotation":"PostMapping","URI":"\"account/change-password\"","className":"AccountResource","line":85,"otherAnnotations":["@PostMapping(\"account/change-password\")","@EnforceAtLeastStudent"]}]},{"filePath":"AthenaResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTextFeedbackSuggestions","httpMethodAnnotation":"GetMapping","URI":"\"athena/text-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\"","className":"AthenaResource","line":160,"otherAnnotations":["@GetMapping(\"athena/text-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingFeedbackSuggestions","httpMethodAnnotation":"GetMapping","URI":"\"athena/programming-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\"","className":"AthenaResource","line":174,"otherAnnotations":["@GetMapping(\"athena/programming-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingFeedbackSuggestions","httpMethodAnnotation":"GetMapping","URI":"\"athena/modeling-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\"","className":"AthenaResource","line":188,"otherAnnotations":["@GetMapping(\"athena/modeling-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableModulesForTextExercises","httpMethodAnnotation":"GetMapping","URI":"\"athena/courses/{courseId}/text-exercises/available-modules\"","className":"AthenaResource","line":201,"otherAnnotations":["@GetMapping(\"athena/courses/{courseId}/text-exercises/available-modules\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableModulesForProgrammingExercises","httpMethodAnnotation":"GetMapping","URI":"\"athena/courses/{courseId}/programming-exercises/available-modules\"","className":"AthenaResource","line":213,"otherAnnotations":["@GetMapping(\"athena/courses/{courseId}/programming-exercises/available-modules\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableModulesForModelingExercises","httpMethodAnnotation":"GetMapping","URI":"\"athena/courses/{courseId}/modeling-exercises/available-modules\"","className":"AthenaResource","line":225,"otherAnnotations":["@GetMapping(\"athena/courses/{courseId}/modeling-exercises/available-modules\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/submissions/{submissionId}/repository\"","className":"AthenaResource","line":251,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/submissions/{submissionId}/repository\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"getTemplateRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/repository/template\"","className":"AthenaResource","line":267,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/repository/template\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"getSolutionRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/repository/solution\"","className":"AthenaResource","line":283,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/repository/solution\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"getTestRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/repository/tests\"","className":"AthenaResource","line":299,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/repository/tests\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]}]},{"filePath":"TutorialGroupSessionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOneOfTutorialGroup","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\"","className":"TutorialGroupSessionResource","line":102,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\"","className":"TutorialGroupSessionResource","line":125,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"updateAttendanceCount","httpMethodAnnotation":"PatchMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/attendance-count\"","className":"TutorialGroupSessionResource","line":171,"otherAnnotations":["@PatchMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/attendance-count\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"deleteSession","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\"","className":"TutorialGroupSessionResource","line":193,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions\"","className":"TutorialGroupSessionResource","line":213,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"cancel","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/cancel\"","className":"TutorialGroupSessionResource","line":256,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/cancel\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"activate","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/activate\"","className":"TutorialGroupSessionResource","line":284,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/activate\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"TutorialGroupFreePeriodResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOneOfConfiguration","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\"","className":"TutorialGroupFreePeriodResource","line":74,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\"","className":"TutorialGroupFreePeriodResource","line":97,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods\"","className":"TutorialGroupFreePeriodResource","line":145,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"delete","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\"","className":"TutorialGroupFreePeriodResource","line":190,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"TutorialGroupResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTitle","httpMethodAnnotation":"GetMapping","URI":"\"tutorial-groups/{tutorialGroupId}/title\"","className":"TutorialGroupResource","line":132,"otherAnnotations":["@GetMapping(\"tutorial-groups/{tutorialGroupId}/title\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getUniqueCampusValues","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/campus-values\"","className":"TutorialGroupResource","line":148,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/campus-values\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getUniqueLanguageValues","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/language-values\"","className":"TutorialGroupResource","line":166,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/language-values\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getAllForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups\"","className":"TutorialGroupResource","line":183,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getOneOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\"","className":"TutorialGroupResource","line":203,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups\"","className":"TutorialGroupResource","line":222,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"delete","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\"","className":"TutorialGroupResource","line":283,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\"","className":"TutorialGroupResource","line":318,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"deregisterStudent","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/deregister/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"TutorialGroupResource","line":406,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/deregister/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"registerStudent","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"TutorialGroupResource","line":428,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"registerMultipleStudentsToTutorialGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register-multiple\"","className":"TutorialGroupResource","line":455,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register-multiple\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"importRegistrations","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/import\"","className":"TutorialGroupResource","line":477,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/import\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"exportTutorialGroupsToCSV","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/export/csv\"","className":"TutorialGroupResource","line":550,"otherAnnotations":["@GetMapping(value = \"courses/{courseId}/tutorial-groups/export/csv\", produces = \"text/csv\")","@EnforceAtLeastInstructorInCourse","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"exportTutorialGroupsToJSON","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/export/json\"","className":"TutorialGroupResource","line":581,"otherAnnotations":["@GetMapping(value = \"courses/{courseId}/tutorial-groups/export/json\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastInstructorInCourse","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"TutorialGroupsConfigurationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOneOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration\"","className":"TutorialGroupsConfigurationResource","line":69,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups-configuration\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration\"","className":"TutorialGroupsConfigurationResource","line":86,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups-configuration\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}\"","className":"TutorialGroupsConfigurationResource","line":121,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"BonusResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getBonusForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus\"","className":"BonusResource","line":95,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/bonus\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"calculateGradeWithBonus","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus/calculate-raw\"","className":"BonusResource","line":134,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/bonus/calculate-raw\")","@EnforceAdmin","// TODO: Remove the manual configuration once the endpoint gets it's final pre-authorization when the feature releases.\n@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"createBonusForExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus\"","className":"BonusResource","line":163,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/bonus\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateBonus","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\"","className":"BonusResource","line":228,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteBonus","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\"","className":"BonusResource","line":282,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ApollonConversionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"convertApollonModel","httpMethodAnnotation":"PostMapping","URI":"\"apollon/convert-to-pdf\"","className":"ApollonConversionResource","line":42,"otherAnnotations":["@PostMapping(\"apollon/convert-to-pdf\")","@EnforceAtLeastStudent"]}]},{"filePath":"IrisModelsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllModels","httpMethodAnnotation":"GetMapping","URI":"\"iris/models\"","className":"IrisModelsResource","line":36,"otherAnnotations":["@GetMapping(\"iris/models\")","@EnforceAtLeastEditor"]}]},{"filePath":"IrisResource","classRequestMapping":"\"api/iris/\"","endpoints":[{"requestMapping":"\"api/iris/\"","endpoint":"getStatus","httpMethodAnnotation":"GetMapping","URI":"\"status\"","className":"IrisResource","line":37,"otherAnnotations":["@GetMapping(\"status\")","@EnforceAtLeastStudent"]}]},{"filePath":"IrisExerciseChatSessionResource","classRequestMapping":"\"api/iris/exercise-chat/\"","endpoints":[{"requestMapping":"\"api/iris/exercise-chat/\"","endpoint":"getCurrentSessionOrCreateIfNotExists","httpMethodAnnotation":"PostMapping","URI":"\"{exerciseId}/sessions/current\"","className":"IrisExerciseChatSessionResource","line":70,"otherAnnotations":["@PostMapping(\"{exerciseId}/sessions/current\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/iris/exercise-chat/\"","endpoint":"getAllSessions","httpMethodAnnotation":"GetMapping","URI":"\"{exerciseId}/sessions\"","className":"IrisExerciseChatSessionResource","line":96,"otherAnnotations":["@GetMapping(\"{exerciseId}/sessions\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/iris/exercise-chat/\"","endpoint":"createSessionForExercise","httpMethodAnnotation":"PostMapping","URI":"\"{exerciseId}/sessions\"","className":"IrisExerciseChatSessionResource","line":118,"otherAnnotations":["@PostMapping(\"{exerciseId}/sessions\")","@EnforceAtLeastStudentInExercise"]}]},{"filePath":"IrisCourseChatSessionResource","classRequestMapping":"\"api/iris/course-chat/\"","endpoints":[{"requestMapping":"\"api/iris/course-chat/\"","endpoint":"getCurrentSessionOrCreateIfNotExists","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/sessions/current\"","className":"IrisCourseChatSessionResource","line":70,"otherAnnotations":["@PostMapping(\"{courseId}/sessions/current\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/iris/course-chat/\"","endpoint":"getAllSessions","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/sessions\"","className":"IrisCourseChatSessionResource","line":87,"otherAnnotations":["@GetMapping(\"{courseId}/sessions\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/iris/course-chat/\"","endpoint":"createSessionForCourse","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/sessions\"","className":"IrisCourseChatSessionResource","line":109,"otherAnnotations":["@PostMapping(\"{courseId}/sessions\")","@EnforceAtLeastStudentInCourse"]}]},{"filePath":"IrisSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getGlobalSettings","httpMethodAnnotation":"GetMapping","URI":"\"iris/global-iris-settings\"","className":"IrisSettingsResource","line":58,"otherAnnotations":["@GetMapping(\"iris/global-iris-settings\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getRawCourseSettings","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":71,"otherAnnotations":["@GetMapping(\"courses/{courseId}/raw-iris-settings\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getRawProgrammingExerciseSettings","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":86,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/raw-iris-settings\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseSettings","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/iris-settings\"","className":"IrisSettingsResource","line":103,"otherAnnotations":["@GetMapping(\"courses/{courseId}/iris-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExerciseSettings","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/iris-settings\"","className":"IrisSettingsResource","line":122,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/iris-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateCourseSettings","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":140,"otherAnnotations":["@PutMapping(\"courses/{courseId}/raw-iris-settings\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateProgrammingExerciseSettings","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":158,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/raw-iris-settings\")","@EnforceAtLeastInstructor"]}]},{"filePath":"IrisMessageResource","classRequestMapping":"\"api/iris/\"","endpoints":[{"requestMapping":"\"api/iris/\"","endpoint":"getMessages","httpMethodAnnotation":"GetMapping","URI":"\"sessions/{sessionId}/messages\"","className":"IrisMessageResource","line":65,"otherAnnotations":["@GetMapping(\"sessions/{sessionId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/iris/\"","endpoint":"createMessage","httpMethodAnnotation":"PostMapping","URI":"\"sessions/{sessionId}/messages\"","className":"IrisMessageResource","line":83,"otherAnnotations":["@PostMapping(\"sessions/{sessionId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/iris/\"","endpoint":"resendMessage","httpMethodAnnotation":"PostMapping","URI":"\"sessions/{sessionId}/messages/{messageId}/resend\"","className":"IrisMessageResource","line":110,"otherAnnotations":["@PostMapping(\"sessions/{sessionId}/messages/{messageId}/resend\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/iris/\"","endpoint":"rateMessage","httpMethodAnnotation":"PutMapping","URI":"\"sessions/{sessionId}/messages/{messageId}/helpful\"","className":"IrisMessageResource","line":140,"otherAnnotations":["@PutMapping(value = \"sessions/{sessionId}/messages/{messageId}/helpful\")","@EnforceAtLeastStudent"]}]},{"filePath":"TextSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createTextSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/text-submissions\"","className":"TextSubmissionResource","line":107,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/text-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateTextSubmission","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/text-submissions\"","className":"TextSubmissionResource","line":127,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/text-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTextSubmissionWithResults","httpMethodAnnotation":"GetMapping","URI":"\"text-submissions/{submissionId}\"","className":"TextSubmissionResource","line":164,"otherAnnotations":["@GetMapping(\"text-submissions/{submissionId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllTextSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/text-submissions\"","className":"TextSubmissionResource","line":190,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/text-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTextSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/text-submission-without-assessment\"","className":"TextSubmissionResource","line":208,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/text-submission-without-assessment\")","@EnforceAtLeastTutor"]}]},{"filePath":"SubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"deleteSubmission","httpMethodAnnotation":"DeleteMapping","URI":"\"submissions/{submissionId}\"","className":"SubmissionResource","line":105,"otherAnnotations":["@DeleteMapping(\"submissions/{submissionId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getTestRunSubmissionsForAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/test-run-submissions\"","className":"SubmissionResource","line":141,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/test-run-submissions\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsWithComplaintsForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/submissions-with-complaints\"","className":"SubmissionResource","line":179,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/submissions-with-complaints\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsWithMoreFeedbackRequestForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/more-feedback-requests-with-complaints\"","className":"SubmissionResource","line":200,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/more-feedback-requests-with-complaints\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsOnPageWithSize","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/submissions-for-import\"","className":"SubmissionResource","line":219,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/submissions-for-import\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionVersions","httpMethodAnnotation":"GetMapping","URI":"\"submissions/{submissionId}/versions\"","className":"SubmissionResource","line":258,"otherAnnotations":["@GetMapping(\"submissions/{submissionId}/versions\")","@EnforceAtLeastInstructor"]}]},{"filePath":"LtiResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"lti13DeepLinking","httpMethodAnnotation":"PostMapping","URI":"\"lti13/deep-linking/{courseId}\"","className":"LtiResource","line":84,"otherAnnotations":["@PostMapping(\"lti13/deep-linking/{courseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllConfiguredLtiPlatforms","httpMethodAnnotation":"GetMapping","URI":"\"lti-platforms\"","className":"LtiResource","line":112,"otherAnnotations":["@GetMapping(\"lti-platforms\")","@EnforceAtLeastInstructor"]}]},{"filePath":"QuizSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveOrSubmitForLiveMode","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/submissions/live\"","className":"QuizSubmissionResource","line":100,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/submissions/live\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"submitForPractice","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/submissions/practice\"","className":"QuizSubmissionResource","line":125,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/submissions/practice\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"submitForPreview","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/submissions/preview\"","className":"QuizSubmissionResource","line":188,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/submissions/preview\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"submitQuizForExam","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/submissions/exam\"","className":"QuizSubmissionResource","line":226,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/submissions/exam\")","@EnforceAtLeastStudentInExercise"]}]},{"filePath":"StatisticsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getChartData","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/data-for-content\"","className":"StatisticsResource","line":63,"otherAnnotations":["@GetMapping(\"management/statistics/data-for-content\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseStatistics","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/course-statistics\"","className":"StatisticsResource","line":84,"otherAnnotations":["@GetMapping(\"management/statistics/course-statistics\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseStatistics","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/exercise-statistics\"","className":"StatisticsResource","line":98,"otherAnnotations":["@GetMapping(\"management/statistics/exercise-statistics\")","@EnforceAtLeastTutor"]}]},{"filePath":"ConversationMessageResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createMessage","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/messages\"","className":"ConversationMessageResource","line":80,"otherAnnotations":["@PostMapping(\"courses/{courseId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getMessages","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/messages\"","className":"ConversationMessageResource","line":111,"otherAnnotations":["@GetMapping(\"courses/{courseId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateMessage","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/messages/{messageId}\"","className":"ConversationMessageResource","line":161,"otherAnnotations":["@PutMapping(\"courses/{courseId}/messages/{messageId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteMessage","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/messages/{messageId}\"","className":"ConversationMessageResource","line":179,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/messages/{messageId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateDisplayPriority","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/messages/{postId}/display-priority\"","className":"ConversationMessageResource","line":199,"otherAnnotations":["@PutMapping(\"courses/{courseId}/messages/{postId}/display-priority\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"computeSimilarityScoresWitCoursePosts","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/messages/similarity-check\"","className":"ConversationMessageResource","line":213,"otherAnnotations":["@PostMapping(\"courses/{courseId}/messages/similarity-check\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllPostTagsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/messages/tags\"","className":"ConversationMessageResource","line":228,"otherAnnotations":["@GetMapping(\"courses/{courseId}/messages/tags\")","// TODO: unused, delete\n@EnforceAtLeastStudent"]}]},{"filePath":"AnswerMessageResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createAnswerMessage","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/answer-messages\"","className":"AnswerMessageResource","line":47,"otherAnnotations":["@PostMapping(\"courses/{courseId}/answer-messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateAnswerMessage","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/answer-messages/{answerMessageId}\"","className":"AnswerMessageResource","line":67,"otherAnnotations":["@PutMapping(\"courses/{courseId}/answer-messages/{answerMessageId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteAnswerMessage","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/answer-messages/{answerMessageId}\"","className":"AnswerMessageResource","line":85,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/answer-messages/{answerMessageId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ReactionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createReaction","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/postings/reactions\"","className":"ReactionResource","line":50,"otherAnnotations":["@PostMapping(\"courses/{courseId}/postings/reactions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteReaction","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/postings/reactions/{reactionId}\"","className":"ReactionResource","line":72,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/postings/reactions/{reactionId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ConversationResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"getConversationsOfUser","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/conversations\"","className":"ConversationResource","line":82,"otherAnnotations":["@GetMapping(\"{courseId}/conversations\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateIsFavorite","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/conversations/{conversationId}/favorite\"","className":"ConversationResource","line":102,"otherAnnotations":["@PostMapping(\"{courseId}/conversations/{conversationId}/favorite\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateIsHidden","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/conversations/{conversationId}/hidden\"","className":"ConversationResource","line":120,"otherAnnotations":["@PostMapping(\"{courseId}/conversations/{conversationId}/hidden\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateIsMuted","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/conversations/{conversationId}/muted\"","className":"ConversationResource","line":138,"otherAnnotations":["@PostMapping(\"{courseId}/conversations/{conversationId}/muted\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"hasUnreadMessages","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/unread-messages\"","className":"ConversationResource","line":154,"otherAnnotations":["@GetMapping(\"{courseId}/unread-messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"markAsRead","httpMethodAnnotation":"PatchMapping","URI":"\"{courseId}/conversations/{conversationId}/mark-as-read\"","className":"ConversationResource","line":171,"otherAnnotations":["@PatchMapping(\"{courseId}/conversations/{conversationId}/mark-as-read\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"isCodeOfConductAccepted","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/code-of-conduct/agreement\"","className":"ConversationResource","line":190,"otherAnnotations":["@GetMapping(\"{courseId}/code-of-conduct/agreement\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"acceptCodeOfConduct","httpMethodAnnotation":"PatchMapping","URI":"\"{courseId}/code-of-conduct/agreement\"","className":"ConversationResource","line":206,"otherAnnotations":["@PatchMapping(\"{courseId}/code-of-conduct/agreement\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getResponsibleUsersForCodeOfConduct","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/code-of-conduct/responsible-users\"","className":"ConversationResource","line":223,"otherAnnotations":["@GetMapping(\"{courseId}/code-of-conduct/responsible-users\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"searchMembersOfConversation","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/conversations/{conversationId}/members/search\"","className":"ConversationResource","line":249,"otherAnnotations":["@GetMapping(\"{courseId}/conversations/{conversationId}/members/search\")","@EnforceAtLeastStudent"]}]},{"filePath":"OneToOneChatResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"startOneToOneChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/one-to-one-chats\"","className":"OneToOneChatResource","line":71,"otherAnnotations":["@PostMapping(\"{courseId}/one-to-one-chats\")","@EnforceAtLeastStudent"]}]},{"filePath":"ChannelResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"getCourseChannelsOverview","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/channels/overview\"","className":"ChannelResource","line":106,"otherAnnotations":["@GetMapping(\"{courseId}/channels/overview\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getCoursePublicChannelsOverview","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/channels/public-overview\"","className":"ChannelResource","line":135,"otherAnnotations":["@GetMapping(\"{courseId}/channels/public-overview\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getExerciseChannel","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/exercises/{exerciseId}/channel\"","className":"ChannelResource","line":161,"otherAnnotations":["@GetMapping(\"{courseId}/exercises/{exerciseId}/channel\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getLectureChannel","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/lectures/{lectureId}/channel\"","className":"ChannelResource","line":186,"otherAnnotations":["@GetMapping(\"{courseId}/lectures/{lectureId}/channel\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"createChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels\"","className":"ChannelResource","line":212,"otherAnnotations":["@PostMapping(\"{courseId}/channels\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateChannel","httpMethodAnnotation":"PutMapping","URI":"\"{courseId}/channels/{channelId}\"","className":"ChannelResource","line":244,"otherAnnotations":["@PutMapping(\"{courseId}/channels/{channelId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"deleteChannel","httpMethodAnnotation":"DeleteMapping","URI":"\"{courseId}/channels/{channelId}\"","className":"ChannelResource","line":272,"otherAnnotations":["@DeleteMapping(\"{courseId}/channels/{channelId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"archiveChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/archive\"","className":"ChannelResource","line":303,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/archive\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"unArchiveChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/unarchive\"","className":"ChannelResource","line":322,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/unarchive\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"grantChannelModeratorRole","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/grant-channel-moderator\"","className":"ChannelResource","line":342,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/grant-channel-moderator\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"revokeChannelModeratorRole","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/revoke-channel-moderator\"","className":"ChannelResource","line":365,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/revoke-channel-moderator\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"registerUsersToChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/register\"","className":"ChannelResource","line":395,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/register\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"deregisterUsers","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/deregister\"","className":"ChannelResource","line":433,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/deregister\")","@EnforceAtLeastStudent"]}]},{"filePath":"GroupChatResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"startGroupChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/group-chats\"","className":"GroupChatResource","line":80,"otherAnnotations":["@PostMapping(\"{courseId}/group-chats\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateGroupChat","httpMethodAnnotation":"PutMapping","URI":"\"{courseId}/group-chats/{groupChatId}\"","className":"GroupChatResource","line":115,"otherAnnotations":["@PutMapping(\"{courseId}/group-chats/{groupChatId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"registerUsersToGroupChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/group-chats/{groupChatId}/register\"","className":"GroupChatResource","line":139,"otherAnnotations":["@PostMapping(\"{courseId}/group-chats/{groupChatId}/register\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"deregisterUsersFromGroupChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/group-chats/{groupChatId}/deregister\"","className":"GroupChatResource","line":167,"otherAnnotations":["@PostMapping(\"{courseId}/group-chats/{groupChatId}/deregister\")","@EnforceAtLeastStudent"]}]},{"filePath":"ModelingSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createModelingSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/modeling-submissions\"","className":"ModelingSubmissionResource","line":108,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/modeling-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateModelingSubmission","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/modeling-submissions\"","className":"ModelingSubmissionResource","line":128,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/modeling-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllModelingSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/modeling-submissions\"","className":"ModelingSubmissionResource","line":171,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = GET_200_SUBMISSIONS_REASON, response = ModelingSubmission.class, responseContainer = \"List\"), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@GetMapping(\"exercises/{exerciseId}/modeling-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingSubmission","httpMethodAnnotation":"GetMapping","URI":"\"modeling-submissions/{submissionId}\"","className":"ModelingSubmissionResource","line":195,"otherAnnotations":["@GetMapping(\"modeling-submissions/{submissionId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getModelingSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/modeling-submission-without-assessment\"","className":"ModelingSubmissionResource","line":258,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/modeling-submission-without-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getLatestSubmissionForModelingEditor","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/latest-modeling-submission\"","className":"ModelingSubmissionResource","line":300,"otherAnnotations":["@GetMapping(\"participations/{participationId}/latest-modeling-submission\")","@EnforceAtLeastStudent"]}]},{"filePath":"GradingScaleResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getGradingScaleForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":85,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradingScaleForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":102,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllGradingScalesInInstructorGroupOnPage","httpMethodAnnotation":"GetMapping","URI":"\"grading-scales\"","className":"GradingScaleResource","line":120,"otherAnnotations":["@GetMapping(\"grading-scales\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createGradingScaleForCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":135,"otherAnnotations":["@PostMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createGradingScaleForExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":173,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateGradingScaleForCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":201,"otherAnnotations":["@PutMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateGradingScaleForExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":226,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteGradingScaleForCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":251,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteGradingScaleForExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":269,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]}]},{"filePath":"UserResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"searchAllUsers","httpMethodAnnotation":"GetMapping","URI":"\"users/search\"","className":"UserResource","line":96,"otherAnnotations":["@GetMapping(\"users/search\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateUserNotificationDate","httpMethodAnnotation":"PutMapping","URI":"\"users/notification-date\"","className":"UserResource","line":120,"otherAnnotations":["@PutMapping(\"users/notification-date\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateUserNotificationVisibility","httpMethodAnnotation":"PutMapping","URI":"\"users/notification-visibility\"","className":"UserResource","line":135,"otherAnnotations":["@PutMapping(\"users/notification-visibility\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"initializeUser","httpMethodAnnotation":"PutMapping","URI":"\"users/initialize\"","className":"UserResource","line":151,"otherAnnotations":["@PutMapping(\"users/initialize\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"setIrisAcceptedToTimestamp","httpMethodAnnotation":"PutMapping","URI":"\"users/accept-iris\"","className":"UserResource","line":173,"otherAnnotations":["@PutMapping(\"users/accept-iris\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"addSshPublicKey","httpMethodAnnotation":"PutMapping","URI":"\"users/sshpublickey\"","className":"UserResource","line":191,"otherAnnotations":["@PutMapping(\"users/sshpublickey\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteSshPublicKey","httpMethodAnnotation":"DeleteMapping","URI":"\"users/sshpublickey\"","className":"UserResource","line":218,"otherAnnotations":["@DeleteMapping(\"users/sshpublickey\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getVcsAccessToken","httpMethodAnnotation":"GetMapping","URI":"\"users/vcsToken\"","className":"UserResource","line":236,"otherAnnotations":["@GetMapping(\"users/vcsToken\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createVcsAccessToken","httpMethodAnnotation":"PutMapping","URI":"\"users/vcsToken\"","className":"UserResource","line":252,"otherAnnotations":["@PutMapping(\"users/vcsToken\")","@EnforceAtLeastStudent"]}]},{"filePath":"LearningPathResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"enableLearningPathsForCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/learning-paths/enable\"","className":"LearningPathResource","line":108,"otherAnnotations":["@PutMapping(\"courses/{courseId}/learning-paths/enable\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"generateMissingLearningPathsForCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/learning-paths/generate-missing\"","className":"LearningPathResource","line":129,"otherAnnotations":["@PutMapping(\"courses/{courseId}/learning-paths/generate-missing\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathsOnPage","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/learning-paths\"","className":"LearningPathResource","line":147,"otherAnnotations":["@GetMapping(\"courses/{courseId}/learning-paths\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getHealthStatusForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/learning-path-health\"","className":"LearningPathResource","line":162,"otherAnnotations":["@GetMapping(\"courses/{courseId}/learning-path-health\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}\"","className":"LearningPathResource","line":177,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathCompetencyGraph","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competency-graph\"","className":"LearningPathResource","line":196,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competency-graph\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNgxGraph","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/graph\"","className":"LearningPathResource","line":215,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/graph\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNgxPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/path\"","className":"LearningPathResource","line":229,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/path\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getRelativeLearningPathNavigation","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/relative-navigation\"","className":"LearningPathResource","line":246,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/relative-navigation\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNavigation","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/navigation\"","className":"LearningPathResource","line":265,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/navigation\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNavigationOverview","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/navigation-overview\"","className":"LearningPathResource","line":281,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/navigation-overview\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathId","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/learning-path-id\"","className":"LearningPathResource","line":309,"otherAnnotations":["@GetMapping(\"courses/{courseId}/learning-path-id\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"generateLearningPath","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/learning-path\"","className":"LearningPathResource","line":325,"otherAnnotations":["@PostMapping(\"courses/{courseId}/learning-path\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyProgressForLearningPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competency-progress\"","className":"LearningPathResource","line":349,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competency-progress\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyOrderForLearningPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competencies\"","className":"LearningPathResource","line":371,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competencies\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningObjectsForCompetency","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competencies/{competencyId}/learning-objects\"","className":"LearningPathResource","line":393,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competencies/{competencyId}/learning-objects\")","@EnforceAtLeastStudent"]}]},{"filePath":"ScienceSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getScienceSettingsForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"science-settings\"","className":"ScienceSettingsResource","line":61,"otherAnnotations":["@GetMapping(\"science-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"saveScienceSettingsForCurrentUser","httpMethodAnnotation":"PutMapping","URI":"\"science-settings\"","className":"ScienceSettingsResource","line":79,"otherAnnotations":["@PutMapping(\"science-settings\")","@EnforceAtLeastStudent"]}]},{"filePath":"ScienceResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"science","httpMethodAnnotation":"PutMapping","URI":"\"science\"","className":"ScienceResource","line":42,"otherAnnotations":["@PutMapping(value = \"science\")","@FeatureToggle(Feature.Science)","@EnforceAtLeastStudent"]}]},{"filePath":"AdminSystemNotificationResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"createSystemNotification","httpMethodAnnotation":"PostMapping","URI":"\"system-notifications\"","className":"AdminSystemNotificationResource","line":60,"otherAnnotations":["@PostMapping(\"system-notifications\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateSystemNotification","httpMethodAnnotation":"PutMapping","URI":"\"system-notifications\"","className":"AdminSystemNotificationResource","line":81,"otherAnnotations":["@PutMapping(\"system-notifications\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteSystemNotification","httpMethodAnnotation":"DeleteMapping","URI":"\"system-notifications/{notificationId}\"","className":"AdminSystemNotificationResource","line":103,"otherAnnotations":["@DeleteMapping(\"system-notifications/{notificationId}\")","@EnforceAdmin"]}]},{"filePath":"AdminTextAssessmentEventResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getEventsByCourseId","httpMethodAnnotation":"GetMapping","URI":"\"event-insights/text-assessment/events/{courseId}\"","className":"AdminTextAssessmentEventResource","line":38,"otherAnnotations":["@GetMapping(\"event-insights/text-assessment/events/{courseId}\")","@EnforceAdmin"]}]},{"filePath":"AdminDataExportResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"requestDataExportForUser","httpMethodAnnotation":"PostMapping","URI":"\"data-exports/{login}\"","className":"AdminDataExportResource","line":36,"otherAnnotations":["@PostMapping(\"data-exports/{login}\")","@EnforceAdmin"]}]},{"filePath":"AdminExamResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getCurrentAndUpcomingExams","httpMethodAnnotation":"GetMapping","URI":"\"courses/upcoming-exams\"","className":"AdminExamResource","line":40,"otherAnnotations":["@GetMapping(\"courses/upcoming-exams\")","@EnforceAdmin"]}]},{"filePath":"AdminIrisSettingsResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"updateGlobalSettings","httpMethodAnnotation":"PutMapping","URI":"\"iris/global-iris-settings\"","className":"AdminIrisSettingsResource","line":34,"otherAnnotations":["@PutMapping(\"iris/global-iris-settings\")","@EnforceAdmin"]}]},{"filePath":"AdminBuildJobQueueResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getQueuedBuildJobs","httpMethodAnnotation":"GetMapping","URI":"\"queued-jobs\"","className":"AdminBuildJobQueueResource","line":56,"otherAnnotations":["@GetMapping(\"queued-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getRunningBuildJobs","httpMethodAnnotation":"GetMapping","URI":"\"running-jobs\"","className":"AdminBuildJobQueueResource","line":69,"otherAnnotations":["@GetMapping(\"running-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getBuildAgentSummary","httpMethodAnnotation":"GetMapping","URI":"\"build-agents\"","className":"AdminBuildJobQueueResource","line":82,"otherAnnotations":["@GetMapping(\"build-agents\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getBuildAgentDetails","httpMethodAnnotation":"GetMapping","URI":"\"build-agent\"","className":"AdminBuildJobQueueResource","line":96,"otherAnnotations":["@GetMapping(\"build-agent\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelBuildJob","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-job/{buildJobId}\"","className":"AdminBuildJobQueueResource","line":111,"otherAnnotations":["@DeleteMapping(\"cancel-job/{buildJobId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelAllQueuedBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-all-queued-jobs\"","className":"AdminBuildJobQueueResource","line":126,"otherAnnotations":["@DeleteMapping(\"cancel-all-queued-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelAllRunningBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-all-running-jobs\"","className":"AdminBuildJobQueueResource","line":141,"otherAnnotations":["@DeleteMapping(\"cancel-all-running-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelAllRunningBuildJobsForAgent","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-all-running-jobs-for-agent\"","className":"AdminBuildJobQueueResource","line":157,"otherAnnotations":["@DeleteMapping(\"cancel-all-running-jobs-for-agent\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getFinishedBuildJobs","httpMethodAnnotation":"GetMapping","URI":"\"finished-jobs\"","className":"AdminBuildJobQueueResource","line":173,"otherAnnotations":["@GetMapping(\"finished-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getBuildJobStatistics","httpMethodAnnotation":"GetMapping","URI":"\"build-job-statistics\"","className":"AdminBuildJobQueueResource","line":192,"otherAnnotations":["@GetMapping(\"build-job-statistics\")","@EnforceAdmin"]}]},{"filePath":"AdminStandardizedCompetencyResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"createStandardizedCompetency","httpMethodAnnotation":"PostMapping","URI":"\"standardized-competencies\"","className":"AdminStandardizedCompetencyResource","line":63,"otherAnnotations":["@PostMapping(\"standardized-competencies\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateStandardizedCompetency","httpMethodAnnotation":"PutMapping","URI":"\"standardized-competencies/{competencyId}\"","className":"AdminStandardizedCompetencyResource","line":81,"otherAnnotations":["@PutMapping(\"standardized-competencies/{competencyId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteStandardizedCompetency","httpMethodAnnotation":"DeleteMapping","URI":"\"standardized-competencies/{competencyId}\"","className":"AdminStandardizedCompetencyResource","line":99,"otherAnnotations":["@DeleteMapping(\"standardized-competencies/{competencyId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"createKnowledgeArea","httpMethodAnnotation":"PostMapping","URI":"\"standardized-competencies/knowledge-areas\"","className":"AdminStandardizedCompetencyResource","line":117,"otherAnnotations":["@PostMapping(\"standardized-competencies/knowledge-areas\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateKnowledgeArea","httpMethodAnnotation":"PutMapping","URI":"\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\"","className":"AdminStandardizedCompetencyResource","line":136,"otherAnnotations":["@PutMapping(\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteKnowledgeArea","httpMethodAnnotation":"DeleteMapping","URI":"\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\"","className":"AdminStandardizedCompetencyResource","line":153,"otherAnnotations":["@DeleteMapping(\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"importStandardizedCompetencyCatalog","httpMethodAnnotation":"PutMapping","URI":"\"standardized-competencies/import\"","className":"AdminStandardizedCompetencyResource","line":170,"otherAnnotations":["@PutMapping(\"standardized-competencies/import\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"exportStandardizedCompetencyCatalog","httpMethodAnnotation":"GetMapping","URI":"\"standardized-competencies/export\"","className":"AdminStandardizedCompetencyResource","line":186,"otherAnnotations":["@GetMapping(\"standardized-competencies/export\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]}]},{"filePath":"AdminCourseResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getAllGroupsForAllCourses","httpMethodAnnotation":"GetMapping","URI":"\"courses/groups\"","className":"AdminCourseResource","line":92,"otherAnnotations":["@GetMapping(\"courses/groups\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"createCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses\"","className":"AdminCourseResource","line":115,"otherAnnotations":["@PostMapping(value = \"courses\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}\"","className":"AdminCourseResource","line":169,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}\")","@EnforceAdmin"]}]},{"filePath":"AdminStatisticsResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getChartData","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/data\"","className":"AdminStatisticsResource","line":46,"otherAnnotations":["@GetMapping(\"management/statistics/data\")","@EnforceAdmin"]}]},{"filePath":"AdminExerciseResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getUpcomingExercises","httpMethodAnnotation":"GetMapping","URI":"\"exercises/upcoming\"","className":"AdminExerciseResource","line":40,"otherAnnotations":["@GetMapping(\"exercises/upcoming\")","@EnforceAdmin"]}]},{"filePath":"AdminUserResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"createUser","httpMethodAnnotation":"PostMapping","URI":"\"users\"","className":"AdminUserResource","line":110,"otherAnnotations":["@PostMapping(\"users\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateUser","httpMethodAnnotation":"PutMapping","URI":"\"users\"","className":"AdminUserResource","line":146,"otherAnnotations":["@PutMapping(\"users\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getUser","httpMethodAnnotation":"GetMapping","URI":"\"users/{login:\" + Constants.LOGIN_REGEX + \"}\"","className":"AdminUserResource","line":183,"otherAnnotations":["@GetMapping(\"users/{login:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"importUsers","httpMethodAnnotation":"PostMapping","URI":"\"users/import\"","className":"AdminUserResource","line":203,"otherAnnotations":["@PostMapping(\"users/import\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"syncUserViaLdap","httpMethodAnnotation":"PutMapping","URI":"\"users/{userId}/sync-ldap\"","className":"AdminUserResource","line":217,"otherAnnotations":["@PutMapping(\"users/{userId}/sync-ldap\")","@EnforceAdmin","@Profile(\"ldap | ldap-only\")"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAllUsers","httpMethodAnnotation":"GetMapping","URI":"\"users\"","className":"AdminUserResource","line":237,"otherAnnotations":["@GetMapping(\"users\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAuthorities","httpMethodAnnotation":"GetMapping","URI":"\"users/authorities\"","className":"AdminUserResource","line":250,"otherAnnotations":["@GetMapping(\"users/authorities\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteUser","httpMethodAnnotation":"DeleteMapping","URI":"\"users/{login:\" + Constants.LOGIN_REGEX + \"}\"","className":"AdminUserResource","line":262,"otherAnnotations":["@DeleteMapping(\"users/{login:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteUsers","httpMethodAnnotation":"DeleteMapping","URI":"\"users\"","className":"AdminUserResource","line":279,"otherAnnotations":["@DeleteMapping(\"users\")","@EnforceAdmin"]}]},{"filePath":"LogResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getList","httpMethodAnnotation":"GetMapping","URI":"\"logs\"","className":"LogResource","line":35,"otherAnnotations":["@GetMapping(\"logs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"changeLevel","httpMethodAnnotation":"PutMapping","URI":"\"logs\"","className":"LogResource","line":48,"otherAnnotations":["@PutMapping(\"logs\")","@EnforceAdmin"]}]},{"filePath":"AdminPrivacyStatementResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getPrivacyStatementForUpdate","httpMethodAnnotation":"GetMapping","URI":"\"privacy-statement-for-update\"","className":"AdminPrivacyStatementResource","line":42,"otherAnnotations":["@EnforceAdmin","@GetMapping(\"privacy-statement-for-update\")"]},{"requestMapping":"\"api/admin/\"","endpoint":"updatePrivacyStatement","httpMethodAnnotation":"PutMapping","URI":"\"privacy-statement\"","className":"AdminPrivacyStatementResource","line":57,"otherAnnotations":["@EnforceAdmin","@PutMapping(\"privacy-statement\")"]}]},{"filePath":"AdminImprintResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getImprintForUpdate","httpMethodAnnotation":"GetMapping","URI":"\"imprint-for-update\"","className":"AdminImprintResource","line":42,"otherAnnotations":["@GetMapping(\"imprint-for-update\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateImprint","httpMethodAnnotation":"PutMapping","URI":"\"imprint\"","className":"AdminImprintResource","line":57,"otherAnnotations":["@PutMapping(\"imprint\")","@EnforceAdmin"]}]},{"filePath":"AuditResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getAll","httpMethodAnnotation":"GetMapping","URI":"\"audits\"","className":"AuditResource","line":50,"otherAnnotations":["@GetMapping(\"audits\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getByDates","httpMethodAnnotation":"GetMapping","URI":"\"audits\"","className":"AuditResource","line":66,"otherAnnotations":["@GetMapping(value = \"audits\", params = { \"fromDate\", \"toDate\" })","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"get","httpMethodAnnotation":"GetMapping","URI":"\"audits/{id:.+}\"","className":"AuditResource","line":85,"otherAnnotations":["@GetMapping(\"audits/{id:.+}\")","@EnforceAdmin"]}]},{"filePath":"FeatureToggleResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"toggleFeatures","httpMethodAnnotation":"PutMapping","URI":"\"feature-toggle\"","className":"FeatureToggleResource","line":38,"otherAnnotations":["@PutMapping(\"feature-toggle\")","@EnforceAdmin"]}]},{"filePath":"AdminLtiConfigurationResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getLtiPlatformConfiguration","httpMethodAnnotation":"GetMapping","URI":"\"lti-platform/{platformId}\"","className":"AdminLtiConfigurationResource","line":75,"otherAnnotations":["@GetMapping(\"lti-platform/{platformId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteLtiPlatformConfiguration","httpMethodAnnotation":"DeleteMapping","URI":"\"lti-platform/{platformId}\"","className":"AdminLtiConfigurationResource","line":89,"otherAnnotations":["@DeleteMapping(\"lti-platform/{platformId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateLtiPlatformConfiguration","httpMethodAnnotation":"PutMapping","URI":"\"lti-platform\"","className":"AdminLtiConfigurationResource","line":105,"otherAnnotations":["@PutMapping(\"lti-platform\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"addLtiPlatformConfiguration","httpMethodAnnotation":"PostMapping","URI":"\"lti-platform\"","className":"AdminLtiConfigurationResource","line":125,"otherAnnotations":["@PostMapping(\"lti-platform\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"lti13DynamicRegistration","httpMethodAnnotation":"PostMapping","URI":"\"lti13/dynamic-registration\"","className":"AdminLtiConfigurationResource","line":147,"otherAnnotations":["@PostMapping(\"lti13/dynamic-registration\")","@EnforceAdmin"]}]},{"filePath":"AdminOrganizationResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"addCourseToOrganization","httpMethodAnnotation":"PostMapping","URI":"\"organizations/{organizationId}/courses/{courseId}\"","className":"AdminOrganizationResource","line":74,"otherAnnotations":["@PostMapping(\"organizations/{organizationId}/courses/{courseId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"removeCourseFromOrganization","httpMethodAnnotation":"DeleteMapping","URI":"\"organizations/{organizationId}/courses/{courseId}\"","className":"AdminOrganizationResource","line":92,"otherAnnotations":["@DeleteMapping(\"organizations/{organizationId}/courses/{courseId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"addUserToOrganization","httpMethodAnnotation":"PostMapping","URI":"\"organizations/{organizationId}/users/{userLogin}\"","className":"AdminOrganizationResource","line":109,"otherAnnotations":["@PostMapping(\"organizations/{organizationId}/users/{userLogin}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"removeUserFromOrganization","httpMethodAnnotation":"DeleteMapping","URI":"\"organizations/{organizationId}/users/{userLogin}\"","className":"AdminOrganizationResource","line":130,"otherAnnotations":["@DeleteMapping(\"organizations/{organizationId}/users/{userLogin}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"addOrganization","httpMethodAnnotation":"PostMapping","URI":"\"organizations\"","className":"AdminOrganizationResource","line":147,"otherAnnotations":["@PostMapping(\"organizations\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateOrganization","httpMethodAnnotation":"PutMapping","URI":"\"organizations/{organizationId}\"","className":"AdminOrganizationResource","line":163,"otherAnnotations":["@PutMapping(\"organizations/{organizationId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteOrganization","httpMethodAnnotation":"DeleteMapping","URI":"\"organizations/{organizationId}\"","className":"AdminOrganizationResource","line":184,"otherAnnotations":["@DeleteMapping(\"organizations/{organizationId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAllOrganizations","httpMethodAnnotation":"GetMapping","URI":"\"organizations\"","className":"AdminOrganizationResource","line":197,"otherAnnotations":["@GetMapping(\"organizations\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getNumberOfUsersAndCoursesByOrganization","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}/count\"","className":"AdminOrganizationResource","line":212,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}/count\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getNumberOfUsersAndCoursesOfAllOrganizations","httpMethodAnnotation":"GetMapping","URI":"\"organizations/count-all\"","className":"AdminOrganizationResource","line":229,"otherAnnotations":["@GetMapping(\"organizations/count-all\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getOrganizationById","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}\"","className":"AdminOrganizationResource","line":252,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getOrganizationByIdWithUsersAndCourses","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}/full\"","className":"AdminOrganizationResource","line":267,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}/full\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAllOrganizationsByUser","httpMethodAnnotation":"GetMapping","URI":"\"organizations/users/{userId}\"","className":"AdminOrganizationResource","line":281,"otherAnnotations":["@GetMapping(\"organizations/users/{userId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getOrganizationTitle","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}/title\"","className":"AdminOrganizationResource","line":295,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}/title\")","@EnforceAdmin"]}]},{"filePath":"AdminModelingExerciseResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"checkClusters","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}/check-clusters\"","className":"AdminModelingExerciseResource","line":61,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}/check-clusters\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteModelingExerciseClustersAndElements","httpMethodAnnotation":"DeleteMapping","URI":"\"modeling-exercises/{exerciseId}/clusters\"","className":"AdminModelingExerciseResource","line":75,"otherAnnotations":["@DeleteMapping(\"modeling-exercises/{exerciseId}/clusters\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"triggerAutomaticAssessment","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises/{exerciseId}/trigger-automatic-assessment\"","className":"AdminModelingExerciseResource","line":93,"otherAnnotations":["@PostMapping(\"modeling-exercises/{exerciseId}/trigger-automatic-assessment\")","@EnforceAdmin"]}]},{"filePath":"SystemNotificationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllSystemNotifications","httpMethodAnnotation":"GetMapping","URI":"\"system-notifications\"","className":"SystemNotificationResource","line":52,"otherAnnotations":["@GetMapping(\"system-notifications\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getSystemNotification","httpMethodAnnotation":"GetMapping","URI":"\"system-notifications/{notificationId}\"","className":"SystemNotificationResource","line":67,"otherAnnotations":["@GetMapping(\"system-notifications/{notificationId}\")","@EnforceAtLeastEditor"]}]},{"filePath":"ExamUserResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateExamUser","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-users\"","className":"ExamUserResource","line":75,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/exam-users\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"saveUsersImages","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-users-save-images\"","className":"ExamUserResource","line":123,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/exam-users-save-images\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllWhoDidNotSign","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/verify-exam-users\"","className":"ExamUserResource","line":138,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/verify-exam-users\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"isAttendanceChecked","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/attendance\"","className":"ExamUserResource","line":153,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/attendance\")","@EnforceAtLeastStudent"]}]},{"filePath":"QuizParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"startParticipation","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/{exerciseId}/start-participation\"","className":"QuizParticipationResource","line":78,"otherAnnotations":["@PostMapping(\"quiz-exercises/{exerciseId}/start-participation\")","@EnforceAtLeastStudentInExercise"]}]},{"filePath":"ParticipantScoreResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getScoresOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-scores\"","className":"ParticipantScoreResource","line":63,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-scores\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getScoresOfExam","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}/exam-scores\"","className":"ParticipantScoreResource","line":89,"otherAnnotations":["@GetMapping(\"exams/{examId}/exam-scores\")","@EnforceAtLeastInstructor"]}]},{"filePath":"AppleAppSiteAssociationResource","classRequestMapping":"\".well-known/\"","endpoints":[{"requestMapping":"\".well-known/\"","endpoint":"getAppleAppSiteAssociation","httpMethodAnnotation":"GetMapping","URI":"\"apple-app-site-association\"","className":"AppleAppSiteAssociationResource","line":35,"otherAnnotations":["@GetMapping(\"apple-app-site-association\")","@ManualConfig"]}]},{"filePath":"FileUploadAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAssessmentBySubmissionId","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-submissions/{submissionId}/result\"","className":"FileUploadAssessmentResource","line":71,"otherAnnotations":["@Override","@GetMapping(\"file-upload-submissions/{submissionId}/result\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"saveFileUploadAssessment","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-submissions/{submissionId}/feedback\"","className":"FileUploadAssessmentResource","line":86,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"file-upload-submissions/{submissionId}/feedback\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateFileUploadAssessmentAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-submissions/{submissionId}/assessment-after-complaint\"","className":"FileUploadAssessmentResource","line":104,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"file-upload-submissions/{submissionId}/assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-submissions/{submissionId}/cancel-assessment\"","className":"FileUploadAssessmentResource","line":133,"otherAnnotations":["@PutMapping(\"file-upload-submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/file-upload-submissions/{submissionId}/results/{resultId}\"","className":"FileUploadAssessmentResource","line":147,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/file-upload-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"PlantUmlResource","classRequestMapping":"\"api/plantuml/\"","endpoints":[{"requestMapping":"\"api/plantuml/\"","endpoint":"generatePng","httpMethodAnnotation":"GetMapping","URI":"\"png\"","className":"PlantUmlResource","line":44,"otherAnnotations":["@GetMapping(\"png\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/plantuml/\"","endpoint":"generateSvg","httpMethodAnnotation":"GetMapping","URI":"\"svg\"","className":"PlantUmlResource","line":64,"otherAnnotations":["@GetMapping(\"svg\")","@EnforceAtLeastStudent"]}]},{"filePath":"ProgrammingExerciseSolutionEntryResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getSolutionEntry","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/solution-entries/{solutionEntryId}\"","className":"ProgrammingExerciseSolutionEntryResource","line":95,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllSolutionEntries","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":117,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getSolutionEntriesForCodeHint","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":135,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getSolutionEntriesForTestCase","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":160,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createSolutionEntryForTestCase","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":186,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateSolutionEntry","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\"","className":"ProgrammingExerciseSolutionEntryResource","line":212,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"deleteSolutionEntry","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\"","className":"ProgrammingExerciseSolutionEntryResource","line":243,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAllSolutionEntriesForExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":267,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createStructuralSolutionEntries","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/structural-solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":286,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/structural-solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createBehavioralSolutionEntries","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/behavioral-solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":309,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/behavioral-solution-entries\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExerciseGitDiffReportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getGitDiffReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/diff-report\"","className":"ProgrammingExerciseGitDiffReportResource","line":85,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/diff-report\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getGitDiffReportForSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report/{submissionId2}\"","className":"ProgrammingExerciseGitDiffReportResource","line":109,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report/{submissionId2}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGitDiffReportForSubmissionWithTemplate","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report-with-template\"","className":"ProgrammingExerciseGitDiffReportResource","line":139,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report-with-template\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGitDiffReportForCommits","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/commits/{commitHash1}/diff-report/{commitHash2}\"","className":"ProgrammingExerciseGitDiffReportResource","line":169,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/commits/{commitHash1}/diff-report/{commitHash2}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ProgrammingExerciseTaskResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTasks","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/tasks\"","className":"ProgrammingExerciseTaskResource","line":54,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/tasks\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTasksWithUnassignedTask","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/tasks-with-unassigned-test-cases\"","className":"ProgrammingExerciseTaskResource","line":75,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/tasks-with-unassigned-test-cases\")","@EnforceAtLeastTutor"]}]},{"filePath":"ExerciseHintResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExerciseHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints\"","className":"ExerciseHintResource","line":89,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/exercise-hints\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"updateExerciseHint","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\"","className":"ExerciseHintResource","line":127,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getHintTitle","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/title\"","className":"ExerciseHintResource","line":169,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseHint","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\"","className":"ExerciseHintResource","line":185,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseHintsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints\"","className":"ExerciseHintResource","line":212,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getActivatedExerciseHintsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/activated\"","className":"ExerciseHintResource","line":227,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/activated\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableExerciseHintsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/available\"","className":"ExerciseHintResource","line":248,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/available\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"activateExerciseHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/activate\"","className":"ExerciseHintResource","line":274,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/activate\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"rateExerciseHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/rating/{ratingValue}\"","className":"ExerciseHintResource","line":303,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/rating/{ratingValue}\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"deleteExerciseHint","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\"","className":"ExerciseHintResource","line":327,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\")","@EnforceAtLeastEditorInExercise"]}]},{"filePath":"CoverageReportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getLatestFullCoverageReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/full-testwise-coverage-report\"","className":"CoverageReportResource","line":42,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/full-testwise-coverage-report\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getLatestCoverageReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/testwise-coverage-report\"","className":"CoverageReportResource","line":59,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/testwise-coverage-report\")","@EnforceAtLeastTutorInExercise"]}]},{"filePath":"CodeHintResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllCodeHints","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/code-hints\"","className":"CodeHintResource","line":69,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/code-hints\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"generateCodeHintsForExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/code-hints\"","className":"CodeHintResource","line":83,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/code-hints\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"generateDescriptionForCodeHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/generate-description\"","className":"CodeHintResource","line":108,"otherAnnotations":["@Profile(\"iris\")","@PostMapping(\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/generate-description\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"removeSolutionEntryFromCodeHint","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries/{solutionEntryId}\"","className":"CodeHintResource","line":144,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastEditorInExercise"]}]},{"filePath":"FileUploadSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createFileUploadSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/file-upload-submissions\"","className":"FileUploadSubmissionResource","line":108,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/file-upload-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadSubmission","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-submissions/{submissionId}\"","className":"FileUploadSubmissionResource","line":181,"otherAnnotations":["@GetMapping(\"file-upload-submissions/{submissionId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllFileUploadSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/file-upload-submissions\"","className":"FileUploadSubmissionResource","line":233,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/file-upload-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/file-upload-submission-without-assessment\"","className":"FileUploadSubmissionResource","line":249,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/file-upload-submission-without-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getDataForFileUpload","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/file-upload-editor\"","className":"FileUploadSubmissionResource","line":299,"otherAnnotations":["@GetMapping(\"participations/{participationId}/file-upload-editor\")","@EnforceAtLeastStudent"]}]},{"filePath":"RatingResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getRatingForResult","httpMethodAnnotation":"GetMapping","URI":"\"results/{resultId}/rating\"","className":"RatingResource","line":76,"otherAnnotations":["@GetMapping(\"results/{resultId}/rating\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createRatingForResult","httpMethodAnnotation":"PostMapping","URI":"\"results/{resultId}/rating/{ratingValue}\"","className":"RatingResource","line":95,"otherAnnotations":["@PostMapping(\"results/{resultId}/rating/{ratingValue}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateRatingForResult","httpMethodAnnotation":"PutMapping","URI":"\"results/{resultId}/rating/{ratingValue}\"","className":"RatingResource","line":117,"otherAnnotations":["@PutMapping(\"results/{resultId}/rating/{ratingValue}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getRatingForInstructorDashboard","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/rating\"","className":"RatingResource","line":132,"otherAnnotations":["@GetMapping(\"course/{courseId}/rating\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}\"","className":"ExerciseResource","line":140,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseForExampleSolution","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/example-solution\"","className":"ExerciseResource","line":192,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/example-solution\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/for-assessment-dashboard\"","className":"ExerciseResource","line":224,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseTitle","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/title\"","className":"ExerciseResource","line":262,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStatsForExerciseAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/stats-for-assessment-dashboard\"","className":"ExerciseResource","line":275,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/stats-for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"reset","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/reset\"","className":"ExerciseResource","line":291,"otherAnnotations":["@DeleteMapping(\"exercises/{exerciseId}/reset\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseDetails","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/details\"","className":"ExerciseResource","line":307,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"toggleSecondCorrectionEnabled","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/toggle-second-correction\"","className":"ExerciseResource","line":367,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/toggle-second-correction\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLatestDueDate","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/latest-due-date\"","className":"ExerciseResource","line":382,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/latest-due-date\")","@EnforceAtLeastStudent"]}]},{"filePath":"TutorParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"initTutorParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/tutor-participations\"","className":"TutorParticipationResource","line":81,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/tutor-participations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"assessExampleSubmissionForTutorParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/assess-example-submission\"","className":"TutorParticipationResource","line":109,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/assess-example-submission\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTutorParticipationForGuidedTour","httpMethodAnnotation":"DeleteMapping","URI":"\"guided-tour/exercises/{exerciseId}/example-submission\"","className":"TutorParticipationResource","line":136,"otherAnnotations":["@DeleteMapping(\"guided-tour/exercises/{exerciseId}/example-submission\")","@EnforceAtLeastTutor"]}]},{"filePath":"TextExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createTextExercise","httpMethodAnnotation":"PostMapping","URI":"\"text-exercises\"","className":"TextExerciseResource","line":202,"otherAnnotations":["@PostMapping(\"text-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateTextExercise","httpMethodAnnotation":"PutMapping","URI":"\"text-exercises\"","className":"TextExerciseResource","line":247,"otherAnnotations":["@PutMapping(\"text-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getTextExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/text-exercises\"","className":"TextExerciseResource","line":301,"otherAnnotations":["@GetMapping(\"courses/{courseId}/text-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTextExercise","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises/{exerciseId}\"","className":"TextExerciseResource","line":335,"otherAnnotations":["@GetMapping(\"text-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTextExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"text-exercises/{exerciseId}\"","className":"TextExerciseResource","line":371,"otherAnnotations":["@DeleteMapping(\"text-exercises/{exerciseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getDataForTextEditor","httpMethodAnnotation":"GetMapping","URI":"\"text-editor/{participationId}\"","className":"TextExerciseResource","line":392,"otherAnnotations":["@GetMapping(\"text-editor/{participationId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises\"","className":"TextExerciseResource","line":475,"otherAnnotations":["@GetMapping(\"text-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExercise","httpMethodAnnotation":"PostMapping","URI":"\"text-exercises/import/{sourceExerciseId}\"","className":"TextExerciseResource","line":496,"otherAnnotations":["@PostMapping(\"text-exercises/import/{sourceExerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissions","httpMethodAnnotation":"PostMapping","URI":"\"text-exercises/{exerciseId}/export-submissions\"","className":"TextExerciseResource","line":534,"otherAnnotations":["@PostMapping(\"text-exercises/{exerciseId}/export-submissions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismResult","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises/{exerciseId}/plagiarism-result\"","className":"TextExerciseResource","line":560,"otherAnnotations":["@GetMapping(\"text-exercises/{exerciseId}/plagiarism-result\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarism","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises/{exerciseId}/check-plagiarism\"","className":"TextExerciseResource","line":582,"otherAnnotations":["@GetMapping(\"text-exercises/{exerciseId}/check-plagiarism\")","@FeatureToggle(Feature.PlagiarismChecks)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateTextExercise","httpMethodAnnotation":"PutMapping","URI":"\"text-exercises/{exerciseId}/re-evaluate\"","className":"TextExerciseResource","line":610,"otherAnnotations":["@PutMapping(\"text-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor"]}]},{"filePath":"TeamResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createTeam","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/teams\"","className":"TeamResource","line":131,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/teams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTeam","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/teams/{teamId}\"","className":"TeamResource","line":176,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/teams/{teamId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTeam","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/teams/{teamId}\"","className":"TeamResource","line":247,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/teams/{teamId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTeamsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/teams\"","className":"TeamResource","line":271,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/teams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTeam","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/teams/{teamId}\"","className":"TeamResource","line":290,"otherAnnotations":["@DeleteMapping(\"exercises/{exerciseId}/teams/{teamId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"existsTeamByShortName","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/teams/exists\"","className":"TeamResource","line":323,"otherAnnotations":["@GetMapping(\"courses/{courseId}/teams/exists\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"searchTeamInExercise","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/team-search-users\"","className":"TeamResource","line":340,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/team-search-users\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"importTeamsFromList","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/teams/import-from-list\"","className":"TeamResource","line":363,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/teams/import-from-list\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importTeamsFromSourceExercise","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{destinationExerciseId}/teams/import-from-exercise/{sourceExerciseId}\"","className":"TeamResource","line":402,"otherAnnotations":["@PutMapping(\"exercises/{destinationExerciseId}/teams/import-from-exercise/{sourceExerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseWithExercisesAndParticipationsForTeam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/teams/{teamShortName}/with-exercises-and-participations\"","className":"TeamResource","line":447,"otherAnnotations":["@GetMapping(\"courses/{courseId}/teams/{teamShortName}/with-exercises-and-participations\")","@EnforceAtLeastStudent"]}]},{"filePath":"BuildPlanResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getBuildPlanForEditor","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/build-plan/for-editor\"","className":"BuildPlanResource","line":53,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/build-plan/for-editor\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"setBuildPlan","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/build-plan\"","className":"BuildPlanResource","line":77,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/build-plan\")","@EnforceAtLeastEditor"]}]},{"filePath":"BuildJobQueueResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getQueuedBuildJobsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/queued-jobs\"","className":"BuildJobQueueResource","line":68,"otherAnnotations":["@GetMapping(\"courses/{courseId}/queued-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getRunningBuildJobsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/running-jobs\"","className":"BuildJobQueueResource","line":86,"otherAnnotations":["@GetMapping(\"courses/{courseId}/running-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cancelBuildJob","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cancel-job/{buildJobId}\"","className":"BuildJobQueueResource","line":105,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cancel-job/{buildJobId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAllQueuedBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cancel-all-queued-jobs\"","className":"BuildJobQueueResource","line":126,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cancel-all-queued-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAllRunningBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cancel-all-running-jobs\"","className":"BuildJobQueueResource","line":146,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cancel-all-running-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getFinishedBuildJobsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/finished-jobs\"","className":"BuildJobQueueResource","line":167,"otherAnnotations":["@GetMapping(\"courses/{courseId}/finished-jobs\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getBuildJobStatistics","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/build-job-statistics\"","className":"BuildJobQueueResource","line":184,"otherAnnotations":["@GetMapping(\"courses/{courseId}/build-job-statistics\")","@EnforceAtLeastInstructorInCourse"]}]},{"filePath":"BuildLogResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getBuildLogForBuildJob","httpMethodAnnotation":"GetMapping","URI":"\"build-log/{buildJobId}\"","className":"BuildLogResource","line":41,"otherAnnotations":["@GetMapping(\"build-log/{buildJobId}\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExerciseExportImportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"importProgrammingExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/import/{sourceExerciseId}\"","className":"ProgrammingExerciseExportImportResource","line":185,"otherAnnotations":["@PostMapping(\"programming-exercises/import/{sourceExerciseId}\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"importProgrammingExerciseFromFile","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/programming-exercises/import-from-file\"","className":"ProgrammingExerciseExportImportResource","line":291,"otherAnnotations":["@PostMapping(\"courses/{courseId}/programming-exercises/import-from-file\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"exportInstructorExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-instructor-exercise\"","className":"ProgrammingExerciseExportImportResource","line":318,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-instructor-exercise\")","@EnforceAtLeastInstructor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportInstructorRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-instructor-repository/{repositoryType}\"","className":"ProgrammingExerciseExportImportResource","line":352,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-instructor-repository/{repositoryType}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportInstructorAuxiliaryRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-instructor-auxiliary-repository/{repositoryId}\"","className":"ProgrammingExerciseExportImportResource","line":373,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-instructor-auxiliary-repository/{repositoryId}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissionsByStudentLogins","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/export-repos-by-participant-identifiers/{participantIdentifiers}\"","className":"ProgrammingExerciseExportImportResource","line":419,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/export-repos-by-participant-identifiers/{participantIdentifiers}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissionsByParticipationIds","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/export-repos-by-participation-ids/{participationIds}\"","className":"ProgrammingExerciseExportImportResource","line":464,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/export-repos-by-participation-ids/{participationIds}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportStudentRequestedRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-student-requested-repository\"","className":"ProgrammingExerciseExportImportResource","line":523,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-student-requested-repository\")","@EnforceAtLeastStudent","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportStudentRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-student-repository/{participationId}\"","className":"ProgrammingExerciseExportImportResource","line":550,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-student-repository/{participationId}\")","@EnforceAtLeastStudent","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]}]},{"filePath":"ProgrammingAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateProgrammingManualResultAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"programming-submissions/{submissionId}/assessment-after-complaint\"","className":"ProgrammingAssessmentResource","line":80,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"programming-submissions/{submissionId}/assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PutMapping","URI":"\"programming-submissions/{submissionId}/cancel-assessment\"","className":"ProgrammingAssessmentResource","line":116,"otherAnnotations":["@PutMapping(\"programming-submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveProgrammingAssessment","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/manual-results\"","className":"ProgrammingAssessmentResource","line":130,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"participations/{participationId}/manual-results\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/programming-submissions/{submissionId}/results/{resultId}\"","className":"ProgrammingAssessmentResource","line":201,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/programming-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ProgrammingExerciseParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getParticipationWithLatestResultForStudentParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/student-participation-with-latest-result-and-feedbacks\"","className":"ProgrammingExerciseParticipationResource","line":106,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/student-participation-with-latest-result-and-feedbacks\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationWithAllResultsForStudentParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/student-participation-with-all-results\"","className":"ProgrammingExerciseParticipationResource","line":129,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/student-participation-with-all-results\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLatestResultWithFeedbacksForProgrammingExerciseParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/latest-result-with-feedbacks\"","className":"ProgrammingExerciseParticipationResource","line":154,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/latest-result-with-feedbacks\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"checkIfParticipationHashResult","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/has-result\"","className":"ProgrammingExerciseParticipationResource","line":178,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/has-result\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLatestPendingSubmission","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/latest-pending-submission\"","className":"ProgrammingExerciseParticipationResource","line":194,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/latest-pending-submission\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLatestPendingSubmissionsByExerciseId","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/latest-pending-submissions\"","className":"ProgrammingExerciseParticipationResource","line":216,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/latest-pending-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"resetRepository","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercise-participations/{participationId}/reset-repository\"","className":"ProgrammingExerciseParticipationResource","line":243,"otherAnnotations":["@PutMapping(\"programming-exercise-participations/{participationId}/reset-repository\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCommitInfosForParticipationRepo","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/commits-info\"","className":"ProgrammingExerciseParticipationResource","line":283,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/commits-info\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCommitHistoryForParticipationRepo","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/commit-history\"","className":"ProgrammingExerciseParticipationResource","line":299,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/commit-history\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCommitHistoryForTemplateSolutionOrTestRepo","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise/{exerciseID}/commit-history/{repositoryType}\"","className":"ProgrammingExerciseParticipationResource","line":317,"otherAnnotations":["@GetMapping(\"programming-exercise/{exerciseID}/commit-history/{repositoryType}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationRepositoryFiles","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/files-content/{commitId}\"","className":"ProgrammingExerciseParticipationResource","line":350,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/files-content/{commitId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationRepositoryFilesForCommitsDetailsView","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise/{exerciseId}/files-content-commit-details/{commitId}\"","className":"ProgrammingExerciseParticipationResource","line":371,"otherAnnotations":["@GetMapping(\"programming-exercise/{exerciseId}/files-content-commit-details/{commitId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ProgrammingExerciseGradingResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"reEvaluateGradedResults","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/grading/re-evaluate\"","className":"ProgrammingExerciseGradingResource","line":67,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/grading/re-evaluate\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradingStatistics","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/grading/statistics\"","className":"ProgrammingExerciseGradingResource","line":90,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/grading/statistics\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createProgrammingExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/setup\"","className":"ProgrammingExerciseResource","line":229,"otherAnnotations":["@PostMapping(\"programming-exercises/setup\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateProgrammingExercise","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises\"","className":"ProgrammingExerciseResource","line":271,"otherAnnotations":["@PutMapping(\"programming-exercises\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateProgrammingExerciseTimeline","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/timeline\"","className":"ProgrammingExerciseResource","line":363,"otherAnnotations":["@PutMapping(\"programming-exercises/timeline\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateProblemStatement","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/problem-statement\"","className":"ProgrammingExerciseResource","line":387,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/problem-statement\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/programming-exercises\"","className":"ProgrammingExerciseResource","line":410,"otherAnnotations":["@GetMapping(\"courses/{courseId}/programming-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}\"","className":"ProgrammingExerciseResource","line":442,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExerciseWithSetupParticipations","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/with-participations\"","className":"ProgrammingExerciseResource","line":477,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/with-participations\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExerciseWithTemplateAndSolutionParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/with-template-and-solution-participation\"","className":"ProgrammingExerciseResource","line":501,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/with-template-and-solution-participation\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"deleteProgrammingExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}\"","className":"ProgrammingExerciseResource","line":520,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"combineTemplateRepositoryCommits","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/combine-template-commits\"","className":"ProgrammingExerciseResource","line":543,"otherAnnotations":["@PutMapping(value = \"programming-exercises/{exerciseId}/combine-template-commits\", produces = MediaType.TEXT_PLAIN_VALUE)","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"generateStructureOracleForExercise","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/generate-tests\"","className":"ProgrammingExerciseResource","line":566,"otherAnnotations":["@PutMapping(value = \"programming-exercises/{exerciseId}/generate-tests\", produces = MediaType.TEXT_PLAIN_VALUE)","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"hasAtLeastOneStudentResult","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/test-case-state\"","className":"ProgrammingExerciseResource","line":615,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/test-case-state\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises\"","className":"ProgrammingExerciseResource","line":635,"otherAnnotations":["@GetMapping(\"programming-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesWithSCAOnPage","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/with-sca\"","className":"ProgrammingExerciseResource","line":653,"otherAnnotations":["@GetMapping(\"programming-exercises/with-sca\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAuxiliaryRepositories","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/auxiliary-repository\"","className":"ProgrammingExerciseResource","line":669,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/auxiliary-repository\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"reset","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/reset\"","className":"ProgrammingExerciseResource","line":691,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/reset\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateProgrammingExercise","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/re-evaluate\"","className":"ProgrammingExerciseResource","line":730,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"deleteTaskWithSolutionEntries","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/tasks\"","className":"ProgrammingExerciseResource","line":758,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/tasks\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"redirectGetSolutionRepositoryFiles","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/solution-files-content\"","className":"ProgrammingExerciseResource","line":780,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/solution-files-content\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"redirectGetTemplateRepositoryFiles","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/template-files-content\"","className":"ProgrammingExerciseResource","line":804,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/template-files-content\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"redirectGetSolutionRepositoryFilesWithoutContent","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/file-names\"","className":"ProgrammingExerciseResource","line":828,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/file-names\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getBuildLogStatistics","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/build-log-statistics\"","className":"ProgrammingExerciseResource","line":850,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/build-log-statistics\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getRepositoryCheckoutDirectories","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/repository-checkout-directories\"","className":"ProgrammingExerciseResource","line":871,"otherAnnotations":["@GetMapping(\"programming-exercises/repository-checkout-directories\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]}]},{"filePath":"ProgrammingExerciseLockResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"unlockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/unlock-all-repositories\"","className":"ProgrammingExerciseLockResource","line":37,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/unlock-all-repositories\")","@EnforceAtLeastInstructorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"lockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/lock-all-repositories\"","className":"ProgrammingExerciseLockResource","line":53,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/lock-all-repositories\")","@EnforceAtLeastInstructorInExercise"]}]},{"filePath":"ProgrammingExerciseTestCaseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTestCases","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/test-cases\"","className":"ProgrammingExerciseTestCaseResource","line":73,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/test-cases\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTestCases","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/update-test-cases\"","className":"ProgrammingExerciseTestCaseResource","line":93,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/update-test-cases\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"resetTestCases","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/reset\"","className":"ProgrammingExerciseTestCaseResource","line":121,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/test-cases/reset\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExercisePlagiarismResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getPlagiarismResult","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/plagiarism-result\"","className":"ProgrammingExercisePlagiarismResource","line":73,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/plagiarism-result\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarism","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/check-plagiarism\"","className":"ProgrammingExercisePlagiarismResource","line":96,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/check-plagiarism\")","@EnforceAtLeastEditor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.PlagiarismChecks })"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarismWithJPlagReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/check-plagiarism-jplag-report\"","className":"ProgrammingExercisePlagiarismResource","line":129,"otherAnnotations":["@GetMapping(value = \"programming-exercises/{exerciseId}/check-plagiarism-jplag-report\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]}]},{"filePath":"ProgrammingSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"triggerBuild","httpMethodAnnotation":"PostMapping","URI":"\"programming-submissions/{participationId}/trigger-build\"","className":"ProgrammingSubmissionResource","line":131,"otherAnnotations":["@PostMapping(\"programming-submissions/{participationId}/trigger-build\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"triggerFailedBuild","httpMethodAnnotation":"PostMapping","URI":"\"programming-submissions/{participationId}/trigger-failed-build\"","className":"ProgrammingSubmissionResource","line":172,"otherAnnotations":["@PostMapping(\"programming-submissions/{participationId}/trigger-failed-build\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"triggerInstructorBuildForExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/trigger-instructor-build-all\"","className":"ProgrammingSubmissionResource","line":213,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/trigger-instructor-build-all\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"triggerInstructorBuildForExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/trigger-instructor-build\"","className":"ProgrammingSubmissionResource","line":235,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/trigger-instructor-build\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getAllProgrammingSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/programming-submissions\"","className":"ProgrammingSubmissionResource","line":267,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/programming-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"lockAndGetProgrammingSubmission","httpMethodAnnotation":"GetMapping","URI":"\"programming-submissions/{submissionId}/lock\"","className":"ProgrammingSubmissionResource","line":302,"otherAnnotations":["@GetMapping(\"programming-submissions/{submissionId}/lock\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/programming-submission-without-assessment\"","className":"ProgrammingSubmissionResource","line":367,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/programming-submission-without-assessment\")","@EnforceAtLeastTutor"]}]},{"filePath":"ComplaintResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createComplaint","httpMethodAnnotation":"PostMapping","URI":"\"complaints\"","className":"ComplaintResource","line":107,"otherAnnotations":["@PostMapping(\"complaints\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintBySubmissionId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":151,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"submissionId\" })","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsForTestRunDashboard","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":196,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"exerciseId\" })","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsByCourseId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":215,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"courseId\", \"complaintType\" })","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsByExerciseId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":257,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"exerciseId\", \"complaintType\" })","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsByCourseIdAndExamId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":294,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"courseId\", \"examId\" })","@EnforceAtLeastInstructor"]}]},{"filePath":"ModelingAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAssessmentBySubmissionId","httpMethodAnnotation":"GetMapping","URI":"\"modeling-submissions/{submissionId}/result\"","className":"ModelingAssessmentResource","line":85,"otherAnnotations":["@Override","@GetMapping(\"modeling-submissions/{submissionId}/result\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getModelingExampleAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercise/{exerciseId}/modeling-submissions/{submissionId}/example-assessment\"","className":"ModelingAssessmentResource","line":99,"otherAnnotations":["@GetMapping(\"exercise/{exerciseId}/modeling-submissions/{submissionId}/example-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveModelingAssessment","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{submissionId}/result/{resultId}/assessment\"","className":"ModelingAssessmentResource","line":115,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = PUT_SUBMIT_ASSESSMENT_200_REASON, response = Result.class), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"modeling-submissions/{submissionId}/result/{resultId}/assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveModelingExampleAssessment","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{exampleSubmissionId}/example-assessment\"","className":"ModelingAssessmentResource","line":133,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = PUT_SUBMIT_ASSESSMENT_200_REASON, response = Result.class), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"modeling-submissions/{exampleSubmissionId}/example-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateModelingAssessmentAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{submissionId}/assessment-after-complaint\"","className":"ModelingAssessmentResource","line":152,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = POST_ASSESSMENT_AFTER_COMPLAINT_200_REASON, response = Result.class), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"modeling-submissions/{submissionId}/assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{submissionId}/cancel-assessment\"","className":"ModelingAssessmentResource","line":187,"otherAnnotations":["@PutMapping(\"modeling-submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/modeling-submissions/{submissionId}/results/{resultId}\"","className":"ModelingAssessmentResource","line":201,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/modeling-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"CourseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}\"","className":"CourseResource","line":228,"otherAnnotations":["@PutMapping(value = \"courses/{courseId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateOnlineCourseConfiguration","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/onlineCourseConfiguration\"","className":"CourseResource","line":373,"otherAnnotations":["@PutMapping(\"courses/{courseId}/onlineCourseConfiguration\")","@EnforceAtLeastInstructor","@Profile(\"lti\")"]},{"requestMapping":"\"api/\"","endpoint":"findAllOnlineCoursesForLtiDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-lti-dashboard\"","className":"CourseResource","line":415,"otherAnnotations":["@GetMapping(\"courses/for-lti-dashboard\")","@EnforceAtLeastInstructor","@Profile(\"lti\")"]},{"requestMapping":"\"api/\"","endpoint":"enrollInCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/enroll\"","className":"CourseResource","line":439,"otherAnnotations":["@PostMapping(\"courses/{courseId}/enroll\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"unenrollFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/unenroll\"","className":"CourseResource","line":458,"otherAnnotations":["@PostMapping(\"courses/{courseId}/unenroll\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourses","httpMethodAnnotation":"GetMapping","URI":"\"courses\"","className":"CourseResource","line":474,"otherAnnotations":["@GetMapping(\"courses\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForImport","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-import\"","className":"CourseResource","line":496,"otherAnnotations":["@GetMapping(\"courses/for-import\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesWithQuizExercises","httpMethodAnnotation":"GetMapping","URI":"\"courses/courses-with-quiz\"","className":"CourseResource","line":511,"otherAnnotations":["@GetMapping(\"courses/courses-with-quiz\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesWithUserStats","httpMethodAnnotation":"GetMapping","URI":"\"courses/with-user-stats\"","className":"CourseResource","line":530,"otherAnnotations":["@GetMapping(\"courses/with-user-stats\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForManagementOverview","httpMethodAnnotation":"GetMapping","URI":"\"courses/course-management-overview\"","className":"CourseResource","line":551,"otherAnnotations":["@GetMapping(\"courses/course-management-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseForEnrollment","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/for-enrollment\"","className":"CourseResource","line":563,"otherAnnotations":["@GetMapping(\"courses/{courseId}/for-enrollment\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForEnrollment","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-enrollment\"","className":"CourseResource","line":581,"otherAnnotations":["@GetMapping(\"courses/for-enrollment\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseForDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/for-dashboard\"","className":"CourseResource","line":598,"otherAnnotations":["@GetMapping(\"courses/{courseId}/for-dashboard\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForDropdown","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-dropdown\"","className":"CourseResource","line":639,"otherAnnotations":["@GetMapping(\"courses/for-dropdown\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-dashboard\"","className":"CourseResource","line":662,"otherAnnotations":["@GetMapping(\"courses/for-dashboard\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForNotifications","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-notifications\"","className":"CourseResource","line":712,"otherAnnotations":["@GetMapping(\"courses/for-notifications\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/for-assessment-dashboard\"","className":"CourseResource","line":726,"otherAnnotations":["@GetMapping(\"courses/{courseId}/for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getStatsForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/stats-for-assessment-dashboard\"","className":"CourseResource","line":751,"otherAnnotations":["@GetMapping(\"courses/{courseId}/stats-for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}\"","className":"CourseResource","line":766,"otherAnnotations":["@GetMapping(\"courses/{courseId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseWithExercises","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/with-exercises\"","className":"CourseResource","line":798,"otherAnnotations":["@GetMapping(\"courses/{courseId}/with-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseWithOrganizations","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/with-organizations\"","className":"CourseResource","line":813,"otherAnnotations":["@GetMapping(\"courses/{courseId}/with-organizations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getLockedSubmissionsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/lockedSubmissions\"","className":"CourseResource","line":828,"otherAnnotations":["@GetMapping(\"courses/{courseId}/lockedSubmissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExercisesForCourseOverview","httpMethodAnnotation":"GetMapping","URI":"\"courses/exercises-for-management-overview\"","className":"CourseResource","line":852,"otherAnnotations":["@GetMapping(\"courses/exercises-for-management-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseStatsForCourseOverview","httpMethodAnnotation":"GetMapping","URI":"\"courses/stats-for-management-overview\"","className":"CourseResource","line":873,"otherAnnotations":["@GetMapping(\"courses/stats-for-management-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"archiveCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/archive\"","className":"CourseResource","line":903,"otherAnnotations":["@PutMapping(\"courses/{courseId}/archive\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"downloadCourseArchive","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/download-archive\"","className":"CourseResource","line":934,"otherAnnotations":["@EnforceAtLeastInstructor","@GetMapping(\"courses/{courseId}/download-archive\")"]},{"requestMapping":"\"api/\"","endpoint":"cleanup","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cleanup\"","className":"CourseResource","line":963,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cleanup\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCategoriesInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/categories\"","className":"CourseResource","line":983,"otherAnnotations":["@GetMapping(\"courses/{courseId}/categories\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getStudentsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/students\"","className":"CourseResource","line":998,"otherAnnotations":["@GetMapping(\"courses/{courseId}/students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"searchStudentsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/students/search\"","className":"CourseResource","line":1013,"otherAnnotations":["@GetMapping(\"courses/{courseId}/students/search\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"searchUsersInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/users/search\"","className":"CourseResource","line":1036,"otherAnnotations":["@GetMapping(\"courses/{courseId}/users/search\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTutorsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutors\"","className":"CourseResource","line":1082,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutors\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getEditorsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/editors\"","className":"CourseResource","line":1096,"otherAnnotations":["@GetMapping(\"courses/{courseId}/editors\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getInstructorsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/instructors\"","className":"CourseResource","line":1110,"otherAnnotations":["@GetMapping(\"courses/{courseId}/instructors\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"searchOtherUsersInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/search-other-users\"","className":"CourseResource","line":1125,"otherAnnotations":["@GetMapping(\"courses/{courseId}/search-other-users\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"searchMembersOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/members/search\"","className":"CourseResource","line":1146,"otherAnnotations":["@GetMapping(\"courses/{courseId}/members/search\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseTitle","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/title\"","className":"CourseResource","line":1167,"otherAnnotations":["@GetMapping(\"courses/{courseId}/title\")","@EnforceAtLeastStudent","@ResponseBody"]},{"requestMapping":"\"api/\"","endpoint":"addStudentToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1182,"otherAnnotations":["@PostMapping(\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addTutorToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1197,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addEditorToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1212,"otherAnnotations":["@PostMapping(\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addInstructorToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1228,"otherAnnotations":["@PostMapping(\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeStudentFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1272,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeTutorFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1287,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeEditorFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1302,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeInstructorFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1318,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseDTOForDetailView","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/management-detail\"","className":"CourseResource","line":1354,"otherAnnotations":["@GetMapping(\"courses/{courseId}/management-detail\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getActiveStudentsForCourseDetailView","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/statistics\"","className":"CourseResource","line":1372,"otherAnnotations":["@GetMapping(\"courses/{courseId}/statistics\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getActiveStudentsForCourseLiveTime","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/statistics-lifetime-overview\"","className":"CourseResource","line":1392,"otherAnnotations":["@GetMapping(\"courses/{courseId}/statistics-lifetime-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"addUsersToCourseGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/{courseGroup}\"","className":"CourseResource","line":1419,"otherAnnotations":["@PostMapping(\"courses/{courseId}/{courseGroup}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfAllowedComplaintsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/allowed-complaints\"","className":"CourseResource","line":1438,"otherAnnotations":["@GetMapping(\"courses/{courseId}/allowed-complaints\")","@EnforceAtLeastStudent"]}]},{"filePath":"ParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"startParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/participations\"","className":"ParticipationResource","line":209,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/participations\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"startPracticeParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/participations/practice\"","className":"ParticipationResource","line":266,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/participations/practice\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"resumeParticipation","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/resume-programming-participation/{participationId}\"","className":"ParticipationResource","line":309,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/resume-programming-participation/{participationId}\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"requestFeedback","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/request-feedback\"","className":"ParticipationResource","line":352,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/request-feedback\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateParticipation","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/participations\"","className":"ParticipationResource","line":430,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/participations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateParticipationDueDates","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/participations/update-individual-due-date\"","className":"ParticipationResource","line":510,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/participations/update-individual-due-date\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllParticipationsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/participations\"","className":"ParticipationResource","line":571,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/participations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllParticipationsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/participations\"","className":"ParticipationResource","line":613,"otherAnnotations":["@GetMapping(\"courses/{courseId}/participations\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationWithLatestResult","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/withLatestResult\"","className":"ParticipationResource","line":674,"otherAnnotations":["@GetMapping(\"participations/{participationId}/withLatestResult\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}\"","className":"ParticipationResource","line":696,"otherAnnotations":["@GetMapping(\"participations/{participationId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationBuildArtifact","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/buildArtifact\"","className":"ParticipationResource","line":712,"otherAnnotations":["@GetMapping(\"participations/{participationId}/buildArtifact\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/participation\"","className":"ParticipationResource","line":731,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/participation\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteParticipation","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}\"","className":"ParticipationResource","line":819,"otherAnnotations":["@DeleteMapping(\"participations/{participationId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteParticipationForGuidedTour","httpMethodAnnotation":"DeleteMapping","URI":"\"guided-tour/participations/{participationId}\"","className":"ParticipationResource","line":842,"otherAnnotations":["@DeleteMapping(\"guided-tour/participations/{participationId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"cleanupBuildPlan","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/cleanupBuildPlan\"","className":"ParticipationResource","line":894,"otherAnnotations":["@PutMapping(\"participations/{participationId}/cleanupBuildPlan\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsOfParticipation","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/submissions\"","className":"ParticipationResource","line":937,"otherAnnotations":["@GetMapping(\"participations/{participationId}/submissions\")","@EnforceAtLeastInstructor"]}]},{"filePath":"OrganizationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllOrganizationsByCourse","httpMethodAnnotation":"GetMapping","URI":"\"organizations/courses/{courseId}\"","className":"OrganizationResource","line":43,"otherAnnotations":["@GetMapping(\"organizations/courses/{courseId}\")","@EnforceAtLeastTutor"]}]},{"filePath":"ExerciseScoresChartResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getCourseExerciseScores","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/charts/exercise-scores\"","className":"ExerciseScoresChartResource","line":71,"otherAnnotations":["@GetMapping(\"courses/{courseId}/charts/exercise-scores\")","@EnforceAtLeastStudent"]}]},{"filePath":"TextAssessmentEventResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"addAssessmentEvent","httpMethodAnnotation":"PostMapping","URI":"\"event-insights/text-assessment/events\"","className":"TextAssessmentEventResource","line":83,"otherAnnotations":["@PostMapping(\"event-insights/text-assessment/events\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfTutorsInvolved","httpMethodAnnotation":"GetMapping","URI":"\"event-insights/text-assessment/courses/{courseId}/text-exercises/{exerciseId}/tutors-involved\"","className":"TextAssessmentEventResource","line":105,"otherAnnotations":["@GetMapping(\"event-insights/text-assessment/courses/{courseId}/text-exercises/{exerciseId}/tutors-involved\")","@EnforceAtLeastInstructor"]}]},{"filePath":"TutorEffortResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"calculateTutorEfforts","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/tutor-effort\"","className":"TutorEffortResource","line":64,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/tutor-effort\")","@EnforceAtLeastInstructor"]}]},{"filePath":"NotificationSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getNotificationSettingsForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"notification-settings\"","className":"NotificationSettingsResource","line":67,"otherAnnotations":["@GetMapping(\"notification-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"saveNotificationSettingsForCurrentUser","httpMethodAnnotation":"PutMapping","URI":"\"notification-settings\"","className":"NotificationSettingsResource","line":88,"otherAnnotations":["@PutMapping(\"notification-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getMutedConversations","httpMethodAnnotation":"GetMapping","URI":"\"muted-conversations\"","className":"NotificationSettingsResource","line":110,"otherAnnotations":["@GetMapping(\"muted-conversations\")","@EnforceAtLeastStudent"]}]},{"filePath":"ExampleSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExampleSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/example-submissions\"","className":"ExampleSubmissionResource","line":88,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/example-submissions\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateExampleSubmission","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/example-submissions\"","className":"ExampleSubmissionResource","line":107,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/example-submissions\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"prepareExampleAssessment","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/prepare-assessment\"","className":"ExampleSubmissionResource","line":126,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/prepare-assessment\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExampleSubmission","httpMethodAnnotation":"GetMapping","URI":"\"example-submissions/{exampleSubmissionId}\"","className":"ExampleSubmissionResource","line":166,"otherAnnotations":["@GetMapping(\"example-submissions/{exampleSubmissionId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteExampleSubmission","httpMethodAnnotation":"DeleteMapping","URI":"\"example-submissions/{exampleSubmissionId}\"","className":"ExampleSubmissionResource","line":189,"otherAnnotations":["@DeleteMapping(\"example-submissions/{exampleSubmissionId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExampleSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/example-submissions/import/{sourceSubmissionId}\"","className":"ExampleSubmissionResource","line":207,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/example-submissions/import/{sourceSubmissionId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"FileUploadExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createFileUploadExercise","httpMethodAnnotation":"PostMapping","URI":"\"file-upload-exercises\"","className":"FileUploadExerciseResource","line":143,"otherAnnotations":["@PostMapping(\"file-upload-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importFileUploadExercise","httpMethodAnnotation":"PostMapping","URI":"\"file-upload-exercises/import/{sourceId}\"","className":"FileUploadExerciseResource","line":181,"otherAnnotations":["@PostMapping(\"file-upload-exercises/import/{sourceId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-exercises\"","className":"FileUploadExerciseResource","line":242,"otherAnnotations":["@GetMapping(\"file-upload-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateFileUploadExercise","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-exercises/{exerciseId}\"","className":"FileUploadExerciseResource","line":259,"otherAnnotations":["@PutMapping(\"file-upload-exercises/{exerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/file-upload-exercises\"","className":"FileUploadExerciseResource","line":301,"otherAnnotations":["@GetMapping(value = \"courses/{courseId}/file-upload-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadExercise","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-exercises/{exerciseId}\"","className":"FileUploadExerciseResource","line":322,"otherAnnotations":["@GetMapping(\"file-upload-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteFileUploadExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"file-upload-exercises/{exerciseId}\"","className":"FileUploadExerciseResource","line":356,"otherAnnotations":["@DeleteMapping(\"file-upload-exercises/{exerciseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissions","httpMethodAnnotation":"PostMapping","URI":"\"file-upload-exercises/{exerciseId}/export-submissions\"","className":"FileUploadExerciseResource","line":376,"otherAnnotations":["@PostMapping(\"file-upload-exercises/{exerciseId}/export-submissions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateFileUploadExercise","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-exercises/{exerciseId}/re-evaluate\"","className":"FileUploadExerciseResource","line":403,"otherAnnotations":["@PutMapping(\"file-upload-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor"]}]},{"filePath":"ExamLockResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"unlockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/unlock-all-repositories\"","className":"ExamLockResource","line":42,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/unlock-all-repositories\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"lockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/lock-all-repositories\"","className":"ExamLockResource","line":61,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/lock-all-repositories\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ApollonDiagramResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createApollonDiagram","httpMethodAnnotation":"PostMapping","URI":"\"course/{courseId}/apollon-diagrams\"","className":"ApollonDiagramResource","line":67,"otherAnnotations":["@PostMapping(\"course/{courseId}/apollon-diagrams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateApollonDiagram","httpMethodAnnotation":"PutMapping","URI":"\"course/{courseId}/apollon-diagrams\"","className":"ApollonDiagramResource","line":96,"otherAnnotations":["@PutMapping(\"course/{courseId}/apollon-diagrams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getDiagramTitle","httpMethodAnnotation":"GetMapping","URI":"\"apollon-diagrams/{diagramId}/title\"","className":"ApollonDiagramResource","line":121,"otherAnnotations":["@GetMapping(\"apollon-diagrams/{diagramId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getDiagramsByCourse","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/apollon-diagrams\"","className":"ApollonDiagramResource","line":134,"otherAnnotations":["@GetMapping(\"course/{courseId}/apollon-diagrams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getApollonDiagram","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\"","className":"ApollonDiagramResource","line":152,"otherAnnotations":["@GetMapping(\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteApollonDiagram","httpMethodAnnotation":"DeleteMapping","URI":"\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\"","className":"ApollonDiagramResource","line":171,"otherAnnotations":["@DeleteMapping(\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\")","@EnforceAtLeastEditor"]}]},{"filePath":"TextAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveTextAssessment","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/results/{resultId}/text-assessment\"","className":"TextAssessmentResource","line":133,"otherAnnotations":["@PutMapping(\"participations/{participationId}/results/{resultId}/text-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveTextExampleAssessment","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment\"","className":"TextAssessmentResource","line":167,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTextExampleAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment/feedback\"","className":"TextAssessmentResource","line":201,"otherAnnotations":["@ResponseStatus(HttpStatus.NO_CONTENT)","@DeleteMapping(\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment/feedback\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"submitTextAssessment","httpMethodAnnotation":"PostMapping","URI":"\"participations/{participationId}/results/{resultId}/submit-text-assessment\"","className":"TextAssessmentResource","line":244,"otherAnnotations":["@PostMapping(\"participations/{participationId}/results/{resultId}/submit-text-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTextAssessmentAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/submissions/{submissionId}/text-assessment-after-complaint\"","className":"TextAssessmentResource","line":282,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"participations/{participationId}/submissions/{submissionId}/text-assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PostMapping","URI":"\"participations/{participationId}/submissions/{submissionId}/cancel-assessment\"","className":"TextAssessmentResource","line":316,"otherAnnotations":["@PostMapping(\"participations/{participationId}/submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/text-submissions/{submissionId}/results/{resultId}\"","className":"TextAssessmentResource","line":336,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/text-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"retrieveParticipationForSubmission","httpMethodAnnotation":"GetMapping","URI":"\"text-submissions/{submissionId}/for-assessment\"","className":"TextAssessmentResource","line":356,"otherAnnotations":["@GetMapping(\"text-submissions/{submissionId}/for-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExampleResultForTutor","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/submissions/{submissionId}/example-result\"","className":"TextAssessmentResource","line":432,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/submissions/{submissionId}/example-result\")","@EnforceAtLeastTutor"]}]},{"filePath":"ExerciseGroupResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExerciseGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups\"","className":"ExerciseGroupResource","line":95,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateExerciseGroup","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups\"","className":"ExerciseGroupResource","line":132,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExerciseGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/import-exercise-group\"","className":"ExerciseGroupResource","line":159,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/import-exercise-group\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseGroup","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\"","className":"ExerciseGroupResource","line":180,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseGroupsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups\"","className":"ExerciseGroupResource","line":198,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"deleteExerciseGroup","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\"","className":"ExerciseGroupResource","line":221,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"LectureResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createLecture","httpMethodAnnotation":"PostMapping","URI":"\"lectures\"","className":"LectureResource","line":109,"otherAnnotations":["@PostMapping(\"lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateLecture","httpMethodAnnotation":"PutMapping","URI":"\"lectures\"","className":"LectureResource","line":130,"otherAnnotations":["@PutMapping(\"lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllLecturesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"lectures\"","className":"LectureResource","line":157,"otherAnnotations":["@GetMapping(\"lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getLecturesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/lectures\"","className":"LectureResource","line":171,"otherAnnotations":["@GetMapping(\"courses/{courseId}/lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getLecturesWithSlidesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/lectures-with-slides\"","className":"LectureResource","line":195,"otherAnnotations":["@GetMapping(\"courses/{courseId}/lectures-with-slides\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLecture","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}\"","className":"LectureResource","line":216,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"importLecture","httpMethodAnnotation":"PostMapping","URI":"\"lectures/import/{sourceLectureId}\"","className":"LectureResource","line":242,"otherAnnotations":["@PostMapping(\"lectures/import/{sourceLectureId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"ingestLectures","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/ingest\"","className":"LectureResource","line":271,"otherAnnotations":["@PostMapping(\"courses/{courseId}/ingest\")"]},{"requestMapping":"\"api/\"","endpoint":"getLectureWithDetails","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/details\"","className":"LectureResource","line":295,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLectureWithDetailsAndSlides","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/details-with-slides\"","className":"LectureResource","line":317,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/details-with-slides\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLectureTitle","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/title\"","className":"LectureResource","line":340,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteLecture","httpMethodAnnotation":"DeleteMapping","URI":"\"lectures/{lectureId}\"","className":"LectureResource","line":395,"otherAnnotations":["@DeleteMapping(\"lectures/{lectureId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"StaticCodeAnalysisResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getStaticCodeAnalysisCategories","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/static-code-analysis-categories\"","className":"StaticCodeAnalysisResource","line":69,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/static-code-analysis-categories\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateStaticCodeAnalysisCategories","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/static-code-analysis-categories\"","className":"StaticCodeAnalysisResource","line":89,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/static-code-analysis-categories\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"resetStaticCodeAnalysisCategories","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/static-code-analysis-categories/reset\"","className":"StaticCodeAnalysisResource","line":111,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/static-code-analysis-categories/reset\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importStaticCodeAnalysisCategoriesFromExercise","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}\" + \"/static-code-analysis-categories/import\"","className":"StaticCodeAnalysisResource","line":132,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}\" + \"/static-code-analysis-categories/import\")","@EnforceAtLeastEditor"]}]},{"filePath":"LongFeedbackTextResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getLongFeedback","httpMethodAnnotation":"GetMapping","URI":"\"results/{resultId}/feedbacks/{feedbackId}/long-feedback\"","className":"LongFeedbackTextResource","line":46,"otherAnnotations":["@GetMapping(\"results/{resultId}/feedbacks/{feedbackId}/long-feedback\")","@EnforceAtLeastStudent"]}]},{"filePath":"GradeStepResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllGradeStepsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale/grade-steps\"","className":"GradeStepResource","line":84,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale/grade-steps\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllGradeStepsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps\"","className":"GradeStepResource","line":105,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepsByIdForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale/grade-steps/{gradeStepId}\"","className":"GradeStepResource","line":138,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale/grade-steps/{gradeStepId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepsByIdForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps/{gradeStepId}\"","className":"GradeStepResource","line":157,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps/{gradeStepId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepByPercentageForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale/match-grade-step\"","className":"GradeStepResource","line":175,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale/match-grade-step\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepByPercentageForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale/match-grade-step\"","className":"GradeStepResource","line":212,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale/match-grade-step\")","@EnforceAtLeastStudent"]}]},{"filePath":"QuizExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createQuizExercise","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises\"","className":"QuizExerciseResource","line":215,"otherAnnotations":["@PostMapping(value = \"quiz-exercises\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateQuizExercise","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{exerciseId}\"","className":"QuizExerciseResource","line":260,"otherAnnotations":["@PutMapping(value = \"quiz-exercises/{exerciseId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/quiz-exercises\"","className":"QuizExerciseResource","line":320,"otherAnnotations":["@GetMapping(\"courses/{courseId}/quiz-exercises\")","@EnforceAtLeastTutorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExercisesForExam","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}/quiz-exercises\"","className":"QuizExerciseResource","line":344,"otherAnnotations":["@GetMapping(\"exams/{examId}/quiz-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExercise","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises/{quizExerciseId}\"","className":"QuizExerciseResource","line":368,"otherAnnotations":["@GetMapping(\"quiz-exercises/{quizExerciseId}\")","@EnforceAtLeastTutorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"recalculateStatistics","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises/{quizExerciseId}/recalculate-statistics\"","className":"QuizExerciseResource","line":395,"otherAnnotations":["@GetMapping(\"quiz-exercises/{quizExerciseId}/recalculate-statistics\")","@EnforceAtLeastTutorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExerciseForStudent","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises/{quizExerciseId}/for-student\"","className":"QuizExerciseResource","line":411,"otherAnnotations":["@GetMapping(\"quiz-exercises/{quizExerciseId}/for-student\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"joinBatch","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/{quizExerciseId}/join\"","className":"QuizExerciseResource","line":437,"otherAnnotations":["@PostMapping(\"quiz-exercises/{quizExerciseId}/join\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"addBatch","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizExerciseId}/add-batch\"","className":"QuizExerciseResource","line":465,"otherAnnotations":["@PutMapping(\"quiz-exercises/{quizExerciseId}/add-batch\")","@EnforceAtLeastTutorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"startBatch","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizBatchId}/start-batch\"","className":"QuizExerciseResource","line":491,"otherAnnotations":["@PutMapping(\"quiz-exercises/{quizBatchId}/start-batch\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"performActionForQuizExercise","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizExerciseId}/{action}\"","className":"QuizExerciseResource","line":528,"otherAnnotations":["@PutMapping(\"quiz-exercises/{quizExerciseId}/{action}\")","@EnforceAtLeastEditorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"evaluateQuizExercise","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/{quizExerciseId}/evaluate\"","className":"QuizExerciseResource","line":638,"otherAnnotations":["@PostMapping(\"quiz-exercises/{quizExerciseId}/evaluate\")","@EnforceAtLeastInstructorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"deleteQuizExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"quiz-exercises/{quizExerciseId}\"","className":"QuizExerciseResource","line":658,"otherAnnotations":["@DeleteMapping(\"quiz-exercises/{quizExerciseId}\")","@EnforceAtLeastInstructorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateQuizExercise","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizExerciseId}/re-evaluate\"","className":"QuizExerciseResource","line":706,"otherAnnotations":["@PutMapping(value = \"quiz-exercises/{quizExerciseId}/re-evaluate\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastInstructorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises\"","className":"QuizExerciseResource","line":745,"otherAnnotations":["@GetMapping(\"quiz-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExercise","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/import/{sourceExerciseId}\"","className":"QuizExerciseResource","line":766,"otherAnnotations":["@PostMapping(value = \"quiz-exercises/import/{sourceExerciseId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]}]},{"filePath":"ModelingExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createModelingExercise","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises\"","className":"ModelingExerciseResource","line":160,"otherAnnotations":["@PostMapping(\"modeling-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises\"","className":"ModelingExerciseResource","line":199,"otherAnnotations":["@GetMapping(\"modeling-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateModelingExercise","httpMethodAnnotation":"PutMapping","URI":"\"modeling-exercises\"","className":"ModelingExerciseResource","line":216,"otherAnnotations":["@PutMapping(\"modeling-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/modeling-exercises\"","className":"ModelingExerciseResource","line":266,"otherAnnotations":["@GetMapping(\"courses/{courseId}/modeling-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingExercise","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}\"","className":"ModelingExerciseResource","line":297,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteModelingExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"modeling-exercises/{exerciseId}\"","className":"ModelingExerciseResource","line":324,"otherAnnotations":["@DeleteMapping(\"modeling-exercises/{exerciseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"importExercise","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises/import/{sourceExerciseId}\"","className":"ModelingExerciseResource","line":353,"otherAnnotations":["@PostMapping(\"modeling-exercises/import/{sourceExerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissions","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises/{exerciseId}/export-submissions\"","className":"ModelingExerciseResource","line":381,"otherAnnotations":["@PostMapping(\"modeling-exercises/{exerciseId}/export-submissions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismResult","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}/plagiarism-result\"","className":"ModelingExerciseResource","line":407,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}/plagiarism-result\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarism","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}/check-plagiarism\"","className":"ModelingExerciseResource","line":430,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}/check-plagiarism\")","@FeatureToggle(Feature.PlagiarismChecks)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateModelingExercise","httpMethodAnnotation":"PutMapping","URI":"\"modeling-exercises/{exerciseId}/re-evaluate\"","className":"ModelingExerciseResource","line":458,"otherAnnotations":["@PutMapping(\"modeling-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor"]}]},{"filePath":"StudentExamResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getStudentExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}\"","className":"StudentExamResource","line":175,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams\"","className":"StudentExamResource","line":212,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateWorkingTime","httpMethodAnnotation":"PatchMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/working-time\"","className":"StudentExamResource","line":233,"otherAnnotations":["@PatchMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/working-time\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"attendanceCheck","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}/attendance-check\"","className":"StudentExamResource","line":274,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}/attendance-check\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"submitStudentExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/submit\"","className":"StudentExamResource","line":309,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/student-exams/submit\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamForConduction","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/conduction\"","className":"StudentExamResource","line":361,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/conduction\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTestRunForConduction","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/test-run/{testRunId}/conduction\"","className":"StudentExamResource","line":424,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/test-run/{testRunId}/conduction\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamsForCoursePerUser","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/test-exams-per-user\"","className":"StudentExamResource","line":460,"otherAnnotations":["@GetMapping(\"courses/{courseId}/test-exams-per-user\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamForSummary","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/summary\"","className":"StudentExamResource","line":481,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/summary\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamGradesForSummary","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/grade-summary\"","className":"StudentExamResource","line":528,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/grade-summary\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExamLiveEvents","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/live-events\"","className":"StudentExamResource","line":558,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/live-events\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"findAllTestRunsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/test-runs\"","className":"StudentExamResource","line":588,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/test-runs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createTestRun","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/test-run\"","className":"StudentExamResource","line":607,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/test-run\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"assessUnsubmittedStudentExamsAndEmptySubmissions","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/assess-unsubmitted-and-empty-student-exams\"","className":"StudentExamResource","line":633,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/student-exams/assess-unsubmitted-and-empty-student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTestRun","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/test-run/{testRunId}\"","className":"StudentExamResource","line":668,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/test-run/{testRunId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"startExercises","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/start-exercises\"","className":"StudentExamResource","line":687,"otherAnnotations":["@PostMapping(value = \"courses/{courseId}/exams/{examId}/student-exams/start-exercises\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseStartStatus","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/start-exercises/status\"","className":"StudentExamResource","line":726,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/start-exercises/status\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"submitStudentExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-submitted\"","className":"StudentExamResource","line":829,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-submitted\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"unsubmitStudentExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-unsubmitted\"","className":"StudentExamResource","line":866,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-unsubmitted\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLongestWorkingTimeForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/longest-working-time\"","className":"StudentExamResource","line":901,"otherAnnotations":["@EnforceAtLeastInstructor","@GetMapping(\"courses/{courseId}/exams/{examId}/longest-working-time\")"]}]},{"filePath":"PublicBuildPlanResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getBuildPlan","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/build-plan\"","className":"PublicBuildPlanResource","line":41,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/build-plan\")","@EnforceNothing"]}]},{"filePath":"PublicResultResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"processNewProgrammingExerciseResult","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/new-result\"","className":"PublicResultResource","line":83,"otherAnnotations":["@PostMapping(\"programming-exercises/new-result\")","@EnforceNothing"]}]},{"filePath":"PublicSystemNotificationResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getActiveAndFutureSystemNotifications","httpMethodAnnotation":"GetMapping","URI":"\"system-notifications/active\"","className":"PublicSystemNotificationResource","line":41,"otherAnnotations":["@GetMapping(\"system-notifications/active\")","@EnforceNothing"]}]},{"filePath":"PublicPyrisStatusUpdateResource","classRequestMapping":"\"api/public/pyris/\"","endpoints":[{"requestMapping":"\"api/public/pyris/\"","endpoint":"setStatusOfJob","httpMethodAnnotation":"PostMapping","URI":"\"pipelines/tutor-chat/runs/{runId}/status\"","className":"PublicPyrisStatusUpdateResource","line":58,"otherAnnotations":["// TODO: Rename this to 'exercise-chat' with next breaking Pyris version\n@PostMapping(\"pipelines/tutor-chat/runs/{runId}/status\")","@EnforceNothing"]},{"requestMapping":"\"api/public/pyris/\"","endpoint":"setStatusOfCourseChatJob","httpMethodAnnotation":"PostMapping","URI":"\"pipelines/course-chat/runs/{runId}/status\"","className":"PublicPyrisStatusUpdateResource","line":86,"otherAnnotations":["@PostMapping(\"pipelines/course-chat/runs/{runId}/status\")","@EnforceNothing"]},{"requestMapping":"\"api/public/pyris/\"","endpoint":"setStatusOfIngestionJob","httpMethodAnnotation":"PostMapping","URI":"\"webhooks/ingestion/runs/{runId}/status\"","className":"PublicPyrisStatusUpdateResource","line":112,"otherAnnotations":["@PostMapping(\"webhooks/ingestion/runs/{runId}/status\")","@EnforceNothing"]}]},{"filePath":"PublicProgrammingSubmissionResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"processNewProgrammingSubmission","httpMethodAnnotation":"PostMapping","URI":"\"programming-submissions/{participationId}\"","className":"PublicProgrammingSubmissionResource","line":77,"otherAnnotations":["@PostMapping(\"programming-submissions/{participationId}\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"testCaseChanged","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/test-cases-changed/{exerciseId}\"","className":"PublicProgrammingSubmissionResource","line":143,"otherAnnotations":["@PostMapping(\"programming-exercises/test-cases-changed/{exerciseId}\")","@EnforceNothing"]}]},{"filePath":"PublicLtiResource","classRequestMapping":"","endpoints":[{"requestMapping":"","endpoint":"lti13LaunchRedirect","httpMethodAnnotation":"PostMapping","URI":"LTI13_LOGIN_REDIRECT_PROXY_PATH","className":"PublicLtiResource","line":52,"otherAnnotations":["@PostMapping({ LTI13_LOGIN_REDIRECT_PROXY_PATH, LTI13_DEEPLINK_REDIRECT_PATH })","@EnforceNothing"]},{"requestMapping":"","endpoint":"lti13LaunchRedirect","httpMethodAnnotation":"PostMapping","URI":"LTI13_DEEPLINK_REDIRECT_PATH","className":"PublicLtiResource","line":52,"otherAnnotations":["@PostMapping({ LTI13_LOGIN_REDIRECT_PROXY_PATH, LTI13_DEEPLINK_REDIRECT_PATH })","@EnforceNothing"]}]},{"filePath":"PublicOAuth2JWKSResource","classRequestMapping":"","endpoints":[{"requestMapping":"","endpoint":"getJwkSet","httpMethodAnnotation":"GetMapping","URI":"\".well-known/jwks.json\"","className":"PublicOAuth2JWKSResource","line":40,"otherAnnotations":["@GetMapping(\".well-known/jwks.json\")","@EnforceNothing","@ManualConfig"]}]},{"filePath":"PublicImprintResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getImprint","httpMethodAnnotation":"GetMapping","URI":"\"imprint\"","className":"PublicImprintResource","line":40,"otherAnnotations":["@GetMapping(\"imprint\")","@EnforceNothing"]}]},{"filePath":"PublicPrivacyStatementResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getPrivacyStatement","httpMethodAnnotation":"GetMapping","URI":"\"privacy-statement\"","className":"PublicPrivacyStatementResource","line":40,"otherAnnotations":["@EnforceNothing","@GetMapping(\"privacy-statement\")"]}]},{"filePath":"PublicTimeResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"time","httpMethodAnnotation":"GetMapping","URI":"\"time\"","className":"PublicTimeResource","line":25,"otherAnnotations":["@GetMapping(\"time\")","@EnforceNothing"]}]},{"filePath":"PublicUserJwtResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"authorize","httpMethodAnnotation":"PostMapping","URI":"\"authenticate\"","className":"PublicUserJwtResource","line":70,"otherAnnotations":["@PostMapping(\"authenticate\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"authorizeSAML2","httpMethodAnnotation":"PostMapping","URI":"\"saml2\"","className":"PublicUserJwtResource","line":104,"otherAnnotations":["@PostMapping(\"saml2\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"logout","httpMethodAnnotation":"PostMapping","URI":"\"logout\"","className":"PublicUserJwtResource","line":143,"otherAnnotations":["@PostMapping(\"logout\")","@EnforceNothing"]}]},{"filePath":"PublicAccountResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"registerAccount","httpMethodAnnotation":"PostMapping","URI":"\"register\"","className":"PublicAccountResource","line":83,"otherAnnotations":["@PostMapping(\"register\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"activateAccount","httpMethodAnnotation":"GetMapping","URI":"\"activate\"","className":"PublicAccountResource","line":115,"otherAnnotations":["@GetMapping(\"activate\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"authenticatedLogin","httpMethodAnnotation":"GetMapping","URI":"\"authenticate\"","className":"PublicAccountResource","line":134,"otherAnnotations":["@GetMapping(\"authenticate\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"getAccount","httpMethodAnnotation":"GetMapping","URI":"\"account\"","className":"PublicAccountResource","line":147,"otherAnnotations":["@GetMapping(\"account\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"changeLanguageKey","httpMethodAnnotation":"PostMapping","URI":"\"account/change-language\"","className":"PublicAccountResource","line":180,"otherAnnotations":["@PostMapping(\"account/change-language\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"requestPasswordReset","httpMethodAnnotation":"PostMapping","URI":"\"account/reset-password/init\"","className":"PublicAccountResource","line":198,"otherAnnotations":["@PostMapping(\"account/reset-password/init\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"finishPasswordReset","httpMethodAnnotation":"PostMapping","URI":"\"account/reset-password/finish\"","className":"PublicAccountResource","line":231,"otherAnnotations":["@PostMapping(\"account/reset-password/finish\")","@EnforceNothing"]}]},{"filePath":"DataExportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"requestDataExport","httpMethodAnnotation":"PostMapping","URI":"\"data-exports\"","className":"DataExportResource","line":67,"otherAnnotations":["@PostMapping(\"data-exports\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"downloadDataExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/{dataExportId}\"","className":"DataExportResource","line":108,"otherAnnotations":["@GetMapping(\"data-exports/{dataExportId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"canRequestExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/can-request\"","className":"DataExportResource","line":155,"otherAnnotations":["@GetMapping(\"data-exports/can-request\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"canDownloadAnyExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/can-download\"","className":"DataExportResource","line":167,"otherAnnotations":["@GetMapping(\"data-exports/can-download\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"canDownloadSpecificExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/{dataExportId}/can-download\"","className":"DataExportResource","line":179,"otherAnnotations":["@GetMapping(\"data-exports/{dataExportId}/can-download\")","@EnforceAtLeastStudent"]}]},{"filePath":"ResultResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getResultsForExerciseWithPointsPerCriterion","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/results-with-points-per-criterion\"","className":"ResultResource","line":115,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/results-with-points-per-criterion\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getResult","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/results/{resultId}\"","className":"ResultResource","line":140,"otherAnnotations":["@GetMapping(\"participations/{participationId}/results/{resultId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getResultDetails","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/results/{resultId}/details\"","className":"ResultResource","line":158,"otherAnnotations":["@GetMapping(\"participations/{participationId}/results/{resultId}/details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getBuildJobIdsForResultsOfParticipation","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/results/build-job-ids\"","className":"ResultResource","line":181,"otherAnnotations":["@GetMapping(\"participations/{participationId}/results/build-job-ids\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteResult","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/results/{resultId}\"","className":"ResultResource","line":202,"otherAnnotations":["@DeleteMapping(\"participations/{participationId}/results/{resultId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"createResultForExternalSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/external-submission-results\"","className":"ResultResource","line":221,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/external-submission-results\")","@EnforceAtLeastInstructor"]}]},{"filePath":"GuidedTourSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateGuidedTourSettings","httpMethodAnnotation":"PutMapping","URI":"\"guided-tour-settings\"","className":"GuidedTourSettingsResource","line":46,"otherAnnotations":["@PutMapping(\"guided-tour-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteGuidedTourSetting","httpMethodAnnotation":"DeleteMapping","URI":"\"guided-tour-settings/{settingsKey}\"","className":"GuidedTourSettingsResource","line":60,"otherAnnotations":["@DeleteMapping(\"guided-tour-settings/{settingsKey}\")","@EnforceAtLeastStudent"]}]},{"filePath":"MetricsResource","classRequestMapping":"\"api/metrics/\"","endpoints":[{"requestMapping":"\"api/metrics/\"","endpoint":"getCourseMetricsForUser","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/student\"","className":"MetricsResource","line":41,"otherAnnotations":["@GetMapping(\"course/{courseId}/student\")","@EnforceAtLeastStudentInCourse"]}]},{"filePath":"ExamResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams\"","className":"ExamResource","line":218,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams\"","className":"ExamResource","line":248,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateExamWorkingTime","httpMethodAnnotation":"PatchMapping","URI":"\"courses/{courseId}/exams/{examId}/working-time\"","className":"ExamResource","line":313,"otherAnnotations":["@PatchMapping(\"courses/{courseId}/exams/{examId}/working-time\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createExamAnnouncement","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/announcements\"","className":"ExamResource","line":348,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/announcements\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"importExamWithExercises","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exam-import\"","className":"ExamResource","line":373,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exam-import\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllActiveExams","httpMethodAnnotation":"GetMapping","URI":"\"exams/active\"","className":"ExamResource","line":514,"otherAnnotations":["@GetMapping(\"exams/active\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExamsOnPage","httpMethodAnnotation":"GetMapping","URI":"\"exams\"","className":"ExamResource","line":530,"otherAnnotations":["@GetMapping(\"exams\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExamForImportWithExercises","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}\"","className":"ExamResource","line":543,"otherAnnotations":["@GetMapping(\"exams/{examId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}\"","className":"ExamResource","line":563,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExamTitle","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}/title\"","className":"ExamResource","line":612,"otherAnnotations":["@GetMapping(\"exams/{examId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExamStatistics","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/statistics\"","className":"ExamResource","line":626,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/statistics\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamScore","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/scores\"","className":"ExamResource","line":649,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/scores\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExamForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-for-assessment-dashboard\"","className":"ExamResource","line":667,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exam-for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamForTestRunAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-for-test-run-assessment-dashboard\"","className":"ExamResource","line":704,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exam-for-test-run-assessment-dashboard\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getStatsForExamAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/stats-for-exam-assessment-dashboard\"","className":"ExamResource","line":730,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/stats-for-exam-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams\"","className":"ExamResource","line":747,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamsWithQuizExercisesForUser","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams-for-user\"","className":"ExamResource","line":765,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams-for-user\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cleanup","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/cleanup\"","className":"ExamResource","line":788,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/cleanup\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}\"","className":"ExamResource","line":810,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"resetExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/reset\"","className":"ExamResource","line":834,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/reset\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addStudentToExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"ExamResource","line":858,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"generateStudentExams","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/generate-student-exams\"","className":"ExamResource","line":890,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/generate-student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"generateMissingStudentExams","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/generate-missing-student-exams\"","className":"ExamResource","line":935,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/generate-missing-student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"evaluateQuizExercises","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/evaluate-quiz-exercises\"","className":"ExamResource","line":966,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/student-exams/evaluate-quiz-exercises\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addStudentsToExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/students\"","className":"ExamResource","line":999,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"registerCourseStudents","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/register-course-students\"","className":"ExamResource","line":1017,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/register-course-students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeStudentFromExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"ExamResource","line":1044,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeAllStudentsFromExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/students\"","className":"ExamResource","line":1077,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getOwnStudentExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/own-student-exam\"","className":"ExamResource","line":1105,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/own-student-exam\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateOrderOfExerciseGroups","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/exercise-groups-order\"","className":"ExamResource","line":1123,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/exercise-groups-order\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getLatestIndividualEndDateOfExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/latest-end-date\"","className":"ExamResource","line":1162,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/latest-end-date\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getLockedSubmissionsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/lockedSubmissions\"","className":"ExamResource","line":1180,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/lockedSubmissions\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"archiveExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/archive\"","className":"ExamResource","line":1206,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/archive\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"downloadExamArchive","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/download-archive\"","className":"ExamResource","line":1235,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/download-archive\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesWithPotentialPlagiarismForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exercises-with-potential-plagiarism\"","className":"ExamResource","line":1268,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exercises-with-potential-plagiarism\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllSuspiciousExamSessions","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/suspicious-sessions\"","className":"ExamResource","line":1302,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/suspicious-sessions\")","@EnforceAtLeastInstructor"]}]}] \ No newline at end of file diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json index d55648326e00..3d697912c662 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json @@ -9,12 +9,12 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@eslint/js": "^9.6.0", - "@types/eslint__js": "^8.42.3", - "@types/node": "20.14.08", - "eslint": "^8.57.0", - "typescript": "^5.5.3", - "typescript-eslint": "^7.15.0" + "@eslint/js": "9.9.0", + "@types/eslint__js": "8.42.3", + "@types/node": "22.4.2", + "eslint": "9.9", + "typescript": "5.5.4", + "typescript-eslint": "8.2.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -41,44 +41,38 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -86,45 +80,47 @@ "node": "*" } }, - "node_modules/@eslint/js": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", - "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -132,6 +128,26 @@ "node": "*" } }, + "node_modules/@eslint/js": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", + "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -145,12 +161,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -219,40 +242,42 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.8.tgz", - "integrity": "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==", + "version": "22.4.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.2.tgz", + "integrity": "sha512-nAvM3Ey230/XzxtyDcJ+VjvlzpzoHwLsF7JaDRfoI0ytO0mVheerNmM45CtA0yOILXwXXxOrcUWH3wltX+7PSw==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", - "integrity": "sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/type-utils": "7.15.0", - "@typescript-eslint/utils": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -261,26 +286,27 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -289,16 +315,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz", - "integrity": "sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -306,26 +333,24 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz", - "integrity": "sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/utils": "7.15.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -333,12 +358,13 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -346,13 +372,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz", - "integrity": "sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -361,7 +388,7 @@ "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -374,55 +401,52 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.15.0.tgz", - "integrity": "sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0" + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz", - "integrity": "sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", + "@typescript-eslint/types": "8.2.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -435,6 +459,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -444,6 +469,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -483,13 +509,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -505,6 +533,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -514,6 +543,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -526,6 +556,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -612,6 +643,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -619,18 +651,6 @@ "node": ">=8" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -644,41 +664,38 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", + "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", @@ -692,23 +709,32 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -726,15 +752,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -745,6 +762,19 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -758,17 +788,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -791,6 +835,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -812,6 +857,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -820,13 +866,15 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -843,6 +891,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -854,7 +903,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -872,15 +922,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -888,6 +939,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -912,51 +964,25 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "ISC" }, "node_modules/glob-parent": { "version": "6.0.2", @@ -970,38 +996,14 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1012,6 +1014,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -1031,7 +1034,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", @@ -1056,6 +1060,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1076,23 +1081,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1119,6 +1107,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -1143,6 +1132,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1154,13 +1144,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -1173,6 +1165,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -1216,6 +1209,7 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1225,6 +1219,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -1238,6 +1233,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1260,15 +1256,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -1321,6 +1308,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -1337,15 +1325,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1360,6 +1339,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1369,6 +1349,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -1390,6 +1371,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1419,6 +1401,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -1433,22 +1416,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -1473,10 +1440,11 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -1510,6 +1478,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1531,6 +1500,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -1561,6 +1531,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -1573,6 +1544,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -1592,23 +1564,12 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1618,25 +1579,23 @@ } }, "node_modules/typescript-eslint": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.15.0.tgz", - "integrity": "sha512-Ta40FhMXBCwHura4X4fncaCVkVcnJ9jnOq5+Lp4lN8F4DzHZtOwZdRvVBiNUGznUDHPwdGnrnwxmUOU2fFQqFA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.2.0.tgz", + "integrity": "sha512-DmnqaPcML0xYwUzgNbM1XaKXpEb7BShYf2P1tkUmmcl8hyeG7Pj08Er7R9bNy6AufabywzJcOybQAtnD/c9DGw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "7.15.0", - "@typescript-eslint/parser": "7.15.0", - "@typescript-eslint/utils": "7.15.0" + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", + "@typescript-eslint/utils": "8.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -1644,16 +1603,18 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -1682,12 +1643,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json index 2cf9dd7ba054..aa79b4aa50ae 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json @@ -6,14 +6,15 @@ "main": "AnalysisOfEndpointConnectionsClient.ts", "license": "MIT", "scripts": { - "start": "node -r esm AnalysisOfEndpointConnectionsClient.ts" + "start": "node -r esm AnalysisOfEndpointConnectionsClient.ts", + "update": "ncu -i --format group" }, "devDependencies": { - "@eslint/js": "9.8.0", + "@eslint/js": "9.9.0", "@types/eslint__js": "8.42.3", - "@types/node": "22.1.0", - "eslint": "9.8", + "@types/node": "22.4.2", + "eslint": "9.9", "typescript": "5.5.4", - "typescript-eslint": "8.0.0" + "typescript-eslint": "8.2.0" } } From 4dc60a8c54b7b21ff85e32bfd15002161de622e6 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Wed, 21 Aug 2024 14:39:18 +0300 Subject: [PATCH 10/10] Development: Update gradle wrapper --- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradlew | 7 +++++-- gradlew.bat | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 zcmY+pRa6|n(lttO3GVLh?(Xh3xVuAe26uONcL=V5;I6?T_zdn2`Oi5I_gl9gx~lft zRjVKRp?B~8Wyrx5$mS3|py!Njy{0Wt4i%@s8v88pK z6fPNA45)|*9+*w5kcg$o)}2g}%JfXe6l9ig4T8ia3Hlw#3f^fAKW63%<~GZJd-0YA z9YjleCs~#Y?V+`#nr+49hhsr$K$k!lg}AZDw@>2j=f7t~5IW6#K|lAX7|^N}lJ)I!km`nrwx> z))1Es16__aXGVzQM0EC8xH+O!nqTFBg9Ci{NwRK*CP<6s`Gq(~#lqb(zOlh6ZDBK* zr$|NDj^s6VanrKa+QC;5>twePaexqRI%RO~OY075y?NN90I|f^(P# zF=b>fZ73b5JzD`#GC3lTQ_B3lMeBWgQUGYnFw*HQC}^z{$6G4j(n4y-pRxPT(d2Wgb%vCH(?+t&Pj z)QM`zc`U`+<~D+9E{4Uj2kc#*6eZMU$4Oj6QMfA^K!rbl`iBix=2sPrs7j@aqIrE zTaZJ2M09>rp$mgyUZ!r2$UK{+DGqgl`n;*qFF~M(r#eh`T{MO?2&j?xgr8FU$u3-` zhRDc_I23LL4)K&xg$^&l-W=!Jp-P(_Ie07q>Je;QLxi8LaEc%;WIacJD_T69egF?7 z;I_Sg_!+qrur8$Hq4grigaiVF>U7uWJ@Hkd&%kmFnQN-P^fq0gB1|uRt!U#X;DnlV zo?yHWTw7g5B;#xxY`adhi4yZn@f(7-Xa(J6S=#d@&rlFw!qfvholE>MEb|VWn^g}G zMSrK&zQ^vDId&ojL!{%{o7?s{7;{+u%L{|tar(gp?Uxq3p?xAysB>0E$eG#$tvkk9 z2Q2gEP17{U6@UD*v({5MP-CTZfvWMItVjb4c;i~WLq&{?Q1(koX&vt7+$z}10{^Id z{KDjGi0JpD7@;~odF__0m|p;5rIrHidOP9^mwKe#-&JX-X@acc)06G{LO1Wu)#gvZ za~y9(fhA%UwkDOVU1LBJ`0ROE z4&)dJKK%mG@+CIm?+wt9f~@xIMr8}UH*K1j| z0pppo{7gv3v{URwxVMeg>Ps!L5IKxm zjac2egjgb0vH5i75$s|sY_RYec#>faqJk|AGgV;v=^%BM(^p{p;(^SVt-88G9f!q; z>p}9E4^f0=01S2pQBE4}9YqE%TV)*hlU^8k9{&=K76+*Ax^r=AkBb%OCP^P2nm0Ri z;D-|Zk?gGeU<12ti2CnPVNA(Pb)02+r|&yTWW-OJO7 zNLb0pps6aN?A~NJp5kj{{IOlf!5KWMleV@-hYLift)D>-7K+tgs=7Ake}oBnIy-y1 z(Hn@Hjw=_(x>dO5ysQsrnE%A*bk0K<-j{1Yqz@#n#jOL^AzCr#wR|WYzqk6i7v)Lf zkXdKxzuu20aP{Tbg$(+9&oh7cd(Uoqqf<#ujb$q4sZ~gxFbQfS zS)kNklyL*{2AELgjZ(LBu*>S(oH5AaJ;YiB@;l@=O%F6B?oanzoYRM^fQ9-<~^=3$H0g^JPMLQo@SZ@QuNvy)tyJ)LSj`+()#fy?{aV4Yg^7dlQ7AQM^3GLCR2dAFR zJjtfKiVqF`l-H_fz0HD|9g>)pOxn}k!vdZ=DO!7Sikm{Z%P6BrRkBS6W?ZB5W&7rT z@uYpf@M@a!z7H&o@-yrcCL^Ff3e7p3T`R9p?@o-acXmbTSa0>ZANzCSgovsd%;i$| zVus`not!oL#(W`L-!9w0jdaECaG4hk{V7IOs676ZquZH~0TX5hDq|)x z6T497l|E?f4)LA>j=S8}b$0LS=I4h|hUFJYJODT8Li@#6kF$k0)@*l{RnM1HQ%?VT ze-Pqlc!~t(oumVC*?5fwR;P6u{tHaZ~*LlD;B)4f? z?lpWfa2P@)g57flVl83Ej%P`2)gGyaPjhvD(%i~{`2b>#3!+y&` z!2nuwHMFA-zUY}f1^0B8<`N)Gr=A4TS@b1qykmd0Pq{?r)+1^^+D(=xasb^Tf!oK9 zBLL+*p6M_#ufgLzgq1zcSwZsZnQWFLC3`Yxdg-2=*tT`J9nrfYt)RF)YryBf8_gW{ zvKbB+oZLehfT)S#<|y1)E0hW^?+AnqPXq9Hu;v3dsMGdr{SVyF63;K<8VcgI#~}1i zLYSBL0K;RTT(;>2x=*!1Di9w0mwr;`CN}kM65|Ay{~z}_^JKOsRaN<~#9O^iiW<5P zYN7r~HV!#Nz~IZU`P>1Xe%4f~K}KcF#X&5kO*G}-)74S*tQ8CietdPcA1Yl;S=Mr# z`#MYY!{s^uo=jn7;k6O%(}fN+*0cWMpt~#n9DR<3NyU?+3D^AgI}S)Cu-Tljg`VY} zX1=fq$?8$DtOeGxE6f8lbS_6Q3C4+LDTO$}_IpM$Xv<|QSC%+Oll^q$y`7o@jD{dp zNDl|&X)r7wETa-#h*d`KXntxI(Y{vLha{$0i7@G8xx^m=c<{lJ9?p-i!^W{%j7-oo z0W^SzZ^(Wkyz*We{lEn%Yhu-ycUOHtrRiVJL4~&S91*D0MrLu}Q>v-Mc?GcWfpyz% zX|UvcN@krFO#@v|CtYM}g|=L3%aMo$E5<@CM%c*;?u>LOTz00@+dt1{yg1y=$h+{|D17U}$*^fE^H&8b431EUE z<9tv0V_#%#&1N#j7AKCj!tTK@J%oFW*ESW<(#Gl#Xs%v<@AitI?s92nLzm<)w3Wkkom1f$gcdUi%g_*jofy&}N#luL<$GVIe{iQkQ)sIHVy zBgItnPBFamrv6Kb{eE($Q(f`ZPeW!Hm%Y@F*OF1sKB{Yy|C>WEv_mfvv-N-jh)B-5 z4a!1WcT@9a+hGaBrc~sz=>G?Q!*Zp^JFRUvBMyNR1;`)j$RhH$6gEyVKhd$&K-CFT zXaWC-Y=fyOnqT84iMn9o5oLEOI(_3fk!W^8-74|q1QhQ|CmT0i=b;6Z3u?E{p7V{? z;f#Q-33!L+4&QQcZ~GAqu$NS{M;u%`+#9=7^Oa5PKvCCCWNG_~l(CidS!+xr-*gg{ z$UQ`_1tLT_9jB=Hckkwu>G{s0b0F4bnR7GibmHo?>TR&<3?D;5Fb#gd8*wYa$$~ar z7epl1qM)L{kwiNjQk}?)CFpNTd?0wAOUZ|gC{Ub|c-7h~+Rm(JbdoRe!RNVBQi!M8 z+~U6E2X&KSA*T6KJvsqwqZl#1&==Dm(#b^&VAKQ>7ygv*Fyr;)q9*^F@dCTg2g!w~ z%hg)UXAUyIpIbLXJv1nZX+a_C)BOH2hUim|>=JHCRf(!dtTidb&*~I!JrfRe+PO>w z@ox$G2a3i9d_N9J=|2$y2m-P&#PTNwe!oLBZFs;z|F5kXvBDn<)WwE0E3$ow=zg3R zK(9;sf0t;VEV3@gAg7jRtnj%-6O@!Hvg*;XcUAw}!=2*aErvB(eQIm(-UGmq^J=XN zTqJo$Y|WKo^HlBF3BXJrA#}7ZLg=r*w`I*~Ix`o&2k8^(0mt8Rp=A>F`&gehhp@Jy z^e^#B2!~$LvNCKugg)8)-G%&THdk~kfextilegP9?#C#()F59U$&eo(h|5>ceo*Em z{PEE79T$YP|Kr7K`WBHbtQwyxFkCl6xX&+oUf90B5xoi3_5KHHCyEE*oPbOQkfMz& z6^hT8_NXd2iWk{q9IKae1{_7hMPH8I7_BMtVOM4 z6jm?E0QJOn$qrgsJ`9w##GB9?G})-GXSQo6(tYS(Q0-Ct$co?Zzl0?NHsDRron?;_ zZZgQg)%XW>P?8_&zoGuF(>Och2kEJXsu1_X&~w87x!b z>~h!a>e7{`p@+#hXF88wI*JeWRZ;J4ev4<}HWf|Z;(7$E!S5l9wzBHFe>^I{2`a;a)QnAwa2xv1e(bq$<}!8o^ofGvYpk7dBR+`*%iE;hUY5 zaHF}OjGO9r*{%lmcK^uFiTHgoUD`^9Nx@~;Bg!V* zuuJ&ti{DQiq7RyJAR94wem{}cPK1J(Yxnn_{=>?USqz-~&QXRStS^s-7TksZ$AEI! z#og36s3JGtGU{CnDHRFtipFqvrE*gw7_K@NN0h+ItTq@4fqN!HeQU1y7*X?9+IfZT4Vxebpt z%#VzgdDK~-&+=Z*#>=n#XUhNvBZp3=Cr41jMqwJkHLf3L7Vm~V#GgJ(Jpii~PmJ#s zA7Ft!{xD@z>9DUb4JbiUBdNEcU4BO$651iN*mp*f)HbRRM`Cx5cR?5IfEcU{IZWwf zz(M6CDv)>xa3x}K6%tP^i15P1&&DOLK=k~+jNR$UK3frSl+|PjSC-dBItvD~LL! z>_g(YYdO4k(5EbPOw+v+;G7~jYm>F@Ai|o`gs%F)F8tDz$dl7Q%aCe|v|$UkAul_R zNlA-beBX^IJU?kgS`E$it7nF4DaI!SJAGq)2P&Few(-|tp z?K+%D3e4{pfkayrcbm0ftu6Ol2ZzdKM+4i!hNP3NRL`EvvZJ3yvNr2MV%igZ4kj``Qrdb_OI$7jWP z;l0DYf&0(-*QcP5zrP`HVznW+SbH63Qx$7_9~NjRNg7eKqI!UJ=XH`g^=t8GiFTu( z?2L{JKEu%jJx&XjNzU(*!ZNmL1@RlJA0G$2_LrAb_7lmjil(GSlSM zwTes`m+3R;3#N~Xg#9owh3ycXV8@ZlaY_16kpPFA={721b~URO4HD3sp%fmkZM}k) zZB0#)kP=RkNB~R-MCk8aljG_bagt4vIb~8)BV%(b8_;)&Kf9GX+%O_cNG|(D$!3&D zL(I8}*LqN5NntipFlN13=`D>6!{D@CFMBH0kW3=HccJV+xW~|$qeFR5i-2{X+iWMu zI2$gepQ)H_B%ip_BlWOQ*|pErXs|4ir{IHccgaIJ84irE{?+$KDABXr&f`jB^V-c% z$$u`uU1YB^{<+UN2cNg#7&0bz@yF?5>j|;)5&IV3wIQp58X#OE-M^$HdyvL|Um5t? zhZlAG!Mz%XkUe3t471JM*Yur}o30vzu6RN7gJyNcf!IItsDO730mcJ*O!~V``y5=3 zNJGp34DZ}wd1H6V`Uuy%es>BiO_aE-S8jzir#$& zyk)@2a5tP$@g%jW^b^JGdo)X@Q%sE`^lDQmY9m%uDFpPX`w9%=yQ+nneMm#OaXcD` z9}{tn5A2b2z9783vL2_jSao?uxJhWJoq%47*RafM4o0@gY(p)F>qT4^XM5GLzV#6j zC+HoGhAne7o_w{WUo(B++z7lU3Y0k1rYv9|TSv0vR-Du(5=VakbbelgZTeDn+a_Wv zq_j-^+Qz1WAl;Zg>ahX|CERbX1V%B!hTKN?M}fGoA07M(WU&NfT&TmN`P@56U2 z^)vLDs|Ln~0iTtn-?KTeQl@T&bskJFuTUS!m+$CS9vnd}8(UMO|Kv6TCfGN9NUu&4 zL{)GTxPq>fwsJ~aU=4Qhuq8*RzDsP(LZh$BHezq&9gK$IS<|DYbm})$QTGCS6T;Dr zEkLct!b+#<1r9OKG@P!f1wm8>=Nz!7OzJm!g<+`?N3;YaA3(P@EL=(sTaRMDD!c8=-XN^4BXp(eVkj$NmEMYPP>YJ4bJ3yUud z<3BeJAJ$6z^TuywnfH5lv#$lgwraNw{IV=tIznPH1DT`v-5yS=!)J<}xxl}uZf9azA2A97Haf!;<3y01hlw?dWNEv@TLi1s-mO4vmIT%O_42nS z$VRWrs9NngqRRkWAnWkn%`Rw@?wH|)7XL`EL5EZu$qyJW31&CB^T_)qwIv!{;E_6 zo-9XAryQRlk-O0>o#-SZO>|6OYq;}<*>Wu1AsVRiXY4f8qb;+sItv3AyS!4Ry+q}) zA!pAB|BmC;=RIOk^^vlsEH(!Q!7_1FK~ZB2err*o!+b(r=m1b?$6d!%zmN+69LXnT z&gRmM+n_R-F@sT*IYv0_mGPvur!u`iWbQO7SqiGFLeY&yga zf`lM&B74FA2C?N@8_z652fjhBEoDUKbP8hL{0{HAF%qDo7)o3=3rg#6)T7%%5^wl% z9R0*S*<~>nzYOdQk2l`9h#t+gJy_xujw6xjV(8S<_DbVg61&pT%Hi42l%D73G?adn znB%UdNM0p}lEF-P2%TAMam2zpQev71e>a$$%i+r~b+D9G9pF|oY_*(-u*89oKsXLY+UIbqq)MQ%(GYS{(*n_S_*RN$*~`zUtab%0aKwhx znc)Yo?{xq1sJCgQD)TeTci1ucvbez9q=A72H(-SB18Kl&6^vHV8^i!p@>iF!DIw17 z+8Q)TNisB7>pwyww4y)yJx*wX6SJO78eLBC-ar1+k$Z9fy;wBD|3kzI{<+l*>PSY^ z_?nLOZaeWbU@C3hfK?X;Di*8CHCPkx2qco6(ZyJdqSzp^TJ_5Lpa0UP{Gy+!b0Lr% z@xYxSjUKoY6L#>$qx~KD$-0=|OF7zhVP~ntMgEALYPIfhj@+ z!;JJ7te>CcovruwHsJH6Lta$nm|%^C@=V-rmhU{+I~0(|XHQ9jt@L7pb{gx#{4r!) zg($FyFTslcgu(~6lYr$nW?)%*l#VJ=R-jxK(x=t1bWlu(nL66T#qj%3aZ@uVhy}Co zDU_q61DD5FqqJ*#c|(M5tV)XBN?Ac^12*q)VN4yKPJ|#==S_`_QD9|0ls!`2)SwuHDRA_OfXQDq3%qW&MZB}Z!=k-9xqev8jHz(H z{^D@cIB~QiK>~wa)A&^Ll^Wi6QgCzU;iv-BHsLBs zH7=jN%|>0S`SjP%M&AF1PNVDp_FZ?2Bm@7`DC&v(pYrw!!yD#4 z6+<=HS0Ln6MhoKxF<%~H`y20{vf#pxh=;j{zY381gvAFekgG|>G1zo8$&az{V=;JR zy_puF4$L$?EMhT?;TpQoR*j16ll`#AS4e96C}yp_aGKkBe?1H|k_;gG-~Xorc<;lI zkB}fB{$c-D2mGA&{rm<*@F5)c3X+6??g~XoEwuzSuch0D@W~P5(2I8v8F$c2$Vw51 zP#YLSBDqtWW^EYBl^QYHF+MA7am6f4DOhwnJM=W9$uvMOsZ%_~?)2C#wb?CkI$7{K zEi)=#|5pFvg^){zK5kpBLjB2kZ+$ZB|L=W|aNwyyb(gC2l7bcpx{E-H@)q6@D6N^xh`{1E%ItF2$eeB_SjI@b2WgTpS1thwg&n`jiIzw^TtXUyB{00($GIq>vbj|}bav}}Q_~wp3>k8!E@hVC;OMUTu|= zAy#vXH*GrUHu7^cNZWe1>y;2(51js9wbu+R3Aa*(wzH9+X0dIsf&gc_x|_LP z>~CF^?(~U}+l~ehe|i>?4eo!xkq&Lk+RR-1duNP#o~>@1x)s&i&u zRaYL@+D&_M|JLI6fHbEr_`U;HgPTh#E3?sB)A$*gqyBgg*ql|a-m*TX5rACbWKCE6 zdeQ`v8m6>g^ugv`p|HY^#1QZrGGUj0^HVDc@{?Q0yhalbBEV{+|HzC^-{&e{5K%z9 z6Bxtnfu1!@Mp+Q&*&~;FOg&*Vm<@4b;{FG0-!UUXX!|)1w}op!B_|7_s~d(+=9Gba zKp8`LaB4D(H=cGcspJ_TjYaOwMb=sGn^gtUVhK!UI~2KKYEE-NC}F>+BEY7IVvy%KRvm00tg!Q`y=er}wpEetX}K@;}(}{s9AzV#q2@ zBy7}->|N?13POrs`;U?(qAG(I$~Gt+Rgw%aNZ_0fs_utVvRJT-7z4!@x36v@=NBX=IqkK{#Kg0w48de@?#Yb4M(Svj5=T+<ONr8-oh7l?Cji@+erqur zFhZ=9|Lk=$`c}v4u`)-!!UI=!9Jo@h&7p4RlS#u! zZ7-prn75JkV?VjptX;@$#`U`{vB!=Z?V`T*FBF>J?vsML7e6@2GbUteMFfX-TUu{2 zLNIG*;dV)8GV8gAgEf#)X3A>p3^CRka1v?~8x^anBhQ=L=LsOl=&pcOYHo98m##ye z34MtGCDK!`ptl?taGMr5q{!zVc? zG00e){TV?`YA9eB;(lA3lXI?RrB4BYQGk?vOmTIUJED=(`_*gtn2DB-t4WW54as*W zb2kD-lWX>lb$+W!VFakki>B^Vc+u$?NLF>)!U%b@Y}gYJ>m2H=^x0=nsE0TF^Yu0h ztgH8-o1%+jCk(+&`|)tTfEVHq0cMeFa{Uz)X$;fCq%Y=SOWML6bYfeP8j5hktL`KK z(18`XrUn&WN9PtFxh&dX`y~YBsmdhi7Kw%tKzM%^VEhdD<_XkulW-x=JN6OPbFI4@ zzDDRN+f=@{0h*MswwOqG6gJ?{NuHx(y-|FUGsxyZ*x0~$MW(eY>vqq4Fh#t7uzw=- zKB?|!0N~!h^AMdLa)oR!Ca#HZ9&Zf)ghuO<^RN)4twRlygHnQG(BE{cDc5E}OF4;xss6gYyV~EcJvJkX)xNWb=@yw!uq0v-sf^rvkp-;?DPWK@*SEw|V;IH=7 zfQqEV_>DjOPT~8X*J|H8=&RnzK4~S7ML~nLX^%s-Vqc^aWy7N$y57qciZGcqy#=zU zs8hcHiI=D$+RB{|62{ohCTiaML6FI4Uhzo5D{Jik@poCs0w7F)*w}F4r0sJ~#u-72 z5bK=ANt=M$Dh5NKnxGsg9NRR?WD-x|FhTwBjd zD<-K>44DB~i%frJOfnzh1R>PRY34kw!6~p3M$JLaD1r@`=h)~Ngks-(gdXh^Q?BTP zZ^Zj5w1AwtuR2$~E7s9iZdF}z%pv1em^V2rM{1tLUY@-+Sc0(9jA|iZWml1;v13=U zHf?y@#mb--7z6$ue>`qjhE~brk$AY-RG90~5wcBbDReXR2)pKg{L>;H(DI`U!MLNQ zY9rFJP@ZQ}jlcMh%WSCo%vf+nd0Gmd*F%KMIe>slCUh)8Ma|;M_I+v#;|ueg9oLg; zq2HtZX%&#F7vdpNlkX?}(C7dGC^y#NB#m4%69RzTNrk%4ol~hSI%>2r6B|*ZkW(*P z;u#s;+faHo{tfy+1L^RzWDi*^JR0iY(zJDB36y_QJ+|E-2x+cY z!V8uLNktH~q>WQZuY!Ap66WP|E!0PA1jK~)^8oJVGbspJs6QL!!-5Qm7 zHYI|_`Actg?vDzdg5{86w@GS$G6ANzff7->6i5pB$T4O}`fZ_;{217Om0gN5zTr12 z5mW{hCzCE-QubjxN$TAE-XgI-8dTY@OZmq`y+y_>dk*(qXF0{nam|q@~i}Utp*k{yurq(DW54hkDT4bbg z=_etM?Nf5W^o-HEu9_?&xEqPg^P^mTxLH8n%u$!mWvFG|{&)jtnU&6|5-`~eaNz0%D1BDo`{ zS1N5(KW5v^2eLdd_%`uaRndF@h0Uo6=M|8?b~KbOLZk{HXEnGmtgZXf2inI*1r%n! zQ3&%RI4r{f&dwW~HwH0Ked9b!k6{>_19H z_Ai>5IChDMY(FfMyG%;30?SQ{iV9KyGru62+Y)~qSQ91}b~}w<&*}R&1c#$O`H@~c z5)2S_eXx}M#N{MuGeQS9@#UJB@;W_j50b}jIhxMPloEFQZdvwxiU^RYycTzgK)-vl3LT&$L8~@68$C8~5_U{cR$E#w*x65(qw&eoL@>%ZHvj zWnEMlSh*(o&oy|J7eJ5OD`ssy%F?*Vp?`Cq;FShyl{ZoKCG5g{y}>usznni#8ki(i zO{w@n{iAj1_ooX@+s*!uW60WcH~*bNOT6z%0jVML5};wVrQp~`Uss_{cO2oud_nNA8^B$?07fJ6?iI)Q zuo9G)O-z)DqstrBqf>B%S05hf-wep0@$BFHKSrkZ{za3D)yVzRz)2{wf8(Wp+xyAM z$rtyx$gi3A=V~V!`Q3;BM0$>*VVtxEM|xDL^gew7ydy3Q6YzD&THRz*q33Ms_D;M- zbCx1Ft#UNB)V3bf`~{ImI72OTp^|bF8?G8#FRj+Biy8ET5#rA3sd|0FR@U(LAJ%w8 zS1%n8Z=Amhw)92rIsof=YVWF4jw&F*j1LG@-`+cR0-~2LqXRH8(Ccne{y#MCPncF64U`0uO zWmi$dlii~1D0rLR{qc|_2M!C$t8^=G7xQY)9!#Y331A|>N)EhmyVdLWL9I3YLJ`7? zZmpqUJB>Ni9oiL)^1IK1UoMyhWE{$9M2M6Xi zPKk7GpMsA6vjZbU7~i+u|J6Nk|Ci!Y3UMUT2|`M;JsNQACdJ%ooo9Yt{?A+0hMpxi znEa~~sxC>rKrU6bd=WRb;%wsH>A#j4{({&1GYSNR57Gama(3)2A;SM>qop}l>Jk2* zn1+C$fIxuwzg3mCU#SOqb-wOCb6mBcYlA5+mt<&_J~sBxc(GQtBFINUO~Mr7<-uu($>P HJ4oML2Lo<@i8BwbL^1~GkG`E7C$SEa_ zF^}Ea+#Je`Xy6;#D0FPnSrR%Y!QGA~NA^{oWmW8C<3dr{x6wWQ{4+bzemqV5W$i5~ z=J0jXZ>uZb>DT@0Ks?4QJ{`z?8JWl3$y;2pj#$XP*pv$>$g(z43{YH9KmmR6<#sIn zA`#=0#sgycaBQ^&}Xba!|KaZ8~b30v~nLt z9%#gz_*=~KD{3t^X~l>480*}PhKN=??g`RV|4Ud{Gyyl187MJ}r(#e+H$GEdI+p1s zq_25h;fV)$EPK%Dw-(G=f`yHB-_tttsC!?k7*#!|4a>`Ahj8nm?&n>NRs%jkZW^3-0P_yMP5&*6a26{MRj1&TPF zyE#|c)5uUHzMWx=rMKpuPih*V=S;W3MzIZTw2uTbr}8`p2bm+Z6Sa%vvWAWSf4H)p(+ zSQ8;EvUa#wqWV+9vmIio(%7wukK2SwjUS8Yl%Rq%=~PU)2$Tvm6`1!r3H@U#_|bB0 zmlT1PS3wPB(b&^+@YY7Y$n4l3mV3-X0$>z|gZp6O*Lhzn&?Gad2ZCF;+#95-Y?#y+ z?*l@Yf=a4w{Px=o!N|3~_XKfk&G;fN>Ps&dp2FpA~qD=0~=!NOS@B#XAKKkND>Y{4>rqxrViKD7;?>j8`R` z&G)3FN|dfsxnaI^!d1G%=>AbTTxZWo;n-DLrQ!sj=f~VAOe5zhGS(dgx|!ls62fbX zV@<7Ck^!}R=`Swr?(7w1rY6Nmq~sfXJ?TiKJLn=&SQdEt9$@0 zA+h1Wbwbri0s-stc8yVq;mRa6@kEf8^KXUz&jcic!+avDvvJFa>k0ioWug=T3oPw; zyj4it&0@>_*uI@2=^+T7sL1_!^aJW@Xfo8aC#3^WtQC7fET8b9C} z*u^ue6Ojn z7@(eskJ2+cNnH9~VyfIh<-|7!je~vGy*odz(sk-u$~SrYF3glruZ*W`{sqnS+9=;Z zh{D@MSG91%lr&ua8%$sJF%y1I<|e;EdfJykY8#D$Hc_81n5`$7;1N|b0tvvPLzSg& zn7!5x?T*@rQUKcUhTIjV(rw*5oQYlm5DbEO?60#mohHfbR$3_x#+PZoYi@Vd4`#YgKyTd^!4n{fN~WZDY61sAOm6 zl!d^i*a01QxpWM9Pcl?&{RgO}uq%ErOk5WpECvnfEh!*YP&1Sl)uTN4hg??Vqs~i5 zYsfufz3?{TtwuBN=`0~Qg1PlWH#OGG$ zLLWU17$v``)CE1cds_7kj8mJ{-+l8{DS|zAQ&3|qpOY=!J|kXUhXue9|H>4gqk|n) z-i34GmxLFj8asb3D#D&=ya*a5`C<=o?G;Ev^LV%;l#nH#O=7Nh@z1Do>j6Q;I5S2P zhg|AZbC&|c7}uSJt57s2IK#rSWuararn-02dkptTjo*R{c5o(bWV}_k3BBnKcE|6l zrHl&ezUyw^DmaMdDFVn<8ZY=7_{u{uW&*F<7Al6};lD(u;SB=RpIwI)PTyL=e25h* zGi{lRT}snjbMK~IUx|EGonH+w;iC2Ws)x>=5_{5$m?K z5(*1jMn%u0V1Y%m@`YS3kskt~`1p(rA4uk;Cs!w^KL$w>MH)+cP6|XKr4FfHIATJH z!EGAK4N>1yFR`-zW|w%ByRe#=&kA&#WyUldDGpt!wf-8SFWiSi!5QZL+l7*CE?u!NW1T$<1rdLJ9y3u{_zvHaM?#Rm4 zFk}^1!ffcrB|XK3gsO-s=wr*sUe&^$yN|KxrA)uW00Gu60%pw_+DcUjW`oW<35OC8 zq2{j8SgC}W$?10pvFU83(SL$%C?Kctu3*cs0aa%q!fjn1%xD*Jrm!F3HGR9-C{b?- zHp(cL;ezXMpL@0-1v0DMWddSDNZ5h?q50cOZyVi#bU3&PWE=(hpVn|M4_KYG5h9LffKNRsfhr^=SYiKg?#r&HNMi2@cd4aYL9lw(5_IvQJ zcB*DD()hUSAD^PdA0y|QrVnqwgI@pUXZXjHq3lG2OU&7sPOxxU$Y3&ytj6Qb=2#cC z;{d-{k|xI*bu+Vy&N+}{i(+1me!M;nshY_*&ZQLTGG*xNw#{RpI`3^eGfHck+*38NRgiGahkFethtVY=czJs#)VVc{T65rhU#3Vf?X)8f0)X{w!J3J{z|Sq|%?)nA+zo?$>L9@o`Kc|*7sJo4UjIqu0Ir~S5k^vEH};6K?-dZ0h*m%-1L zf!VC%YbM1~sZOG5zu&Sh>R;(md*_)kGHP)<;OA44W?y53PI%{&@MEN}9TOiqu+1a3AGetBr$c)Ao3OX>iGxmA;^^_alwS818r4Pn&uYe^;z6dh z)68T|AN=hjNdGpF7n>y+RTAZc9&opTXf zqWfK_dUv=mW{p_vN>|(cIkd(+Jy}qnK{IW%X*3!l`^H~FbAHwof+vLZ0C2ZXN1$v7 zgN&R9c8IO`fkR{6U%ERq8FN<1DQYbAN0-pH7EfcA{A&nhT!Be>jj>J!bNRw4NF|}! z1c70_#fkk!VQ!q1h2ff@`yDyrI1`np>*e#D4-Z~*!T^8#o*$V~!8bWQaie?P@KGBb z8rXc!YDL!$3ZgZZ%;-%~0Kn<+d+{xJ$stQbtN8GWV?MCJvzPU|(E(1z;rFw{&6vy) z3*@y%7Tx8rH-p$boS>bLyod?OKRE8v`QSBvGfY6f}_{Zo1q85xoyOF16n~yHx2W ziydUoYLkJmzq|n&2S(O!ZmLdP1(o1Jsq88cX)x3V-BK5eF&0e_0G!5?U7&3KN0`mc zH&Lt)q8!d_VgzxyL^(@xrbp2y)Hmr^V48));RSfE=*Ly0uh9!$3dv-vMZr2URf@l5zdwLjGZB zugY>7_fd_vbV*Qv1?H~>Z%RD%nEeFSI$n$$Lrpc6g>i4+XdBB!%zM$Bhrz5Swzyg? z$~I~n@~-wTBY3-T&pr+|gC+OHDoR?I(eLWa{Z#Rsh>lc~%u0!&R|s0pA*w<7QZ}{i z*AFr~0F3y~f$MGh_HDL7J_1?SxKL}fWIk!$G}`^{)xh*dZ5kK>xGL9>V`WZZg_ z)^Vm)EQK`yfh5KiR(vb&aHvhich z_5o+{d~0+4BEBqYJXyXBIEb1UgVDs;a!N2$9WA>CbfrWryqT25)S4E4)QXBd*3jN} z?phkAt`1rKW?xoLzEm!*IfkH|P>BtECVr0l8-IGk_`UjE#IWkUGqvyS+dMrCnFl<7RCgSMX^qn|Ld_4iYRldO zY&cHhv)GDo8nKvKwAbfyLR%t?9gG?R7~PSD#4D-;?F&!kV59O}neYut5AGbKwy-(U zqyBi=&Mgj|VIo>$u!DHM`R7O?W8-idbePuxiJMH``6c_5L-chKd}=rGC5Gfrc{f!* zWFEBm?l@_b7kzY7%1RQQbG5V<4=ZlkZ%sF74Q|mKOc7Ak7dP2#quiGcZ0_J%7Q?j{ zv9{WFw;n5G-Mn%r#0R;{jLt{yy}9J6rQ(>X9pJ`7Xy?Zv z=lNit#qXaq?CnElK^zF~sG}U5oCpR0T>FH=ZX}Prju$);?;VOhFH8L3I><9P_A|C+ z{;>~dk%9rrq(snjsEm}oUz2FQ21MCG*e?g)?{!&|eg7PX@I+Q0!hL6C7ZVY|g2E>i zr!Ri2@OfEu$)d52+>+cpgh6Z;cLYCZ&EMR0i<^~4&wEu_bdo;y^6}+U2GIQgW$|Od z_jg{O=pU>0-H$P-EOlWyQy#W0r@@_uT}Lg+!d5NxMii7aT1=|qm6BRaWOf{Pws54v zTu=}LR!V(JzI07>QR;;px0+zq=(s+XH-0~rVbmGp8<)7G+Jf)UYs<$Dd>-K+4}CsD zS}KYLmkbRvjwBO3PB%2@j(vOpm)!JABH_E7X^f#V-bzifSaKtE)|QrczC1$sC<<*Y z$hY*3E10fYk`2W09gM_U<2>+r^+ro$Bqh-O7uSa)cfPE_<#^O) zF+5V;-8LaCLKdIh3UB@idQZL`0Vx8`OE#6*1<;8(zi&E7MWB1S%~HAm%axyIHN2vd zA(pJGm_PraB0Aat3~?obWBs?iSc*NhM!{-l_WNCx4@F7I?)5&oI|z{o@JKd1HZ}zf*#}JjK3$ z-;3V*WJZvUcKvSOBH4c7C{fl8oRw8-vfgKQjNiR|KhQ%k6hWNEke(k8w-Ro| z7Y3)FsY-?7%;VT64vRM)l0%&HI~BXkSAOV#F3Bf#|3QLZM%6C{paqLTb3MU-_)`{R zRdfVQ)uX90VCa3ja$8m;cdtxQ*(tNjIfVb%#TCJWeH?o4RY#LWpyZBJHR| z6G-!4W5O^Z8U}e5GfZ!_M{B``ve{r0Z#CXV0x@~X#Pc;}{{ClY_uw^=wWurj0RKnoFzeY` z;gS!PCLCo*c}-hLc?C&wv&>P1hH75=p#;D3{Q8UZ0ctX!b)_@Ur=WCMEuz>pTs$@s z#7bIutL9Pm2FDb~d+H}uBI#pu6R}T{nzpz9U0XLb9lu@=9bTY&PEyFwhHHtXFX~6C zrcg|qqTk(|MIM%KQ<@j=DOjt|V)+8K26wE_CBNnZTg+Z+s}AU|jp6CFoIptG1{J*# z7Ne~l;ba*=bSwAMQ|Vq#fW~+je4PXA91YFzBubNF?ovIOw-$C-8=Ehed{lGD0}(Id zRe4sh8L>&T%{>8o))he}eE;5_ zxoXk3wX?MyNl-xF!q1d$G?=wp^`@09(jU&X zOqZIBI#dN`2PJNdATR3ivtub|nO$dulSaP|e4)WXF1YAGN1pDQIbIjXFG!oC85Mt; zW$eteoL{y^5t4TMRwP$jNPjZFpGsWnGe=jMMqKtcZm9Y9PFZLi*1p@qoKKub^T@2+ zk$@*KYdQ?Z`}<%4ALwk*Yc{(WTf@#u;as(fvE^9{Gk)lWbJP*SjttWofV0s?AB({~l zZI1hZVWFT~W-T?nfMMcnCS4-#6H-MU7H$KxD;yaM46K4Kc@~Q>xzB+QnD_I`b_l3m zo9pRx46b!p?a^&zCDwygqqV3epjs(s0NQI6ARA1n!Yy-qduipxQ& zUAlqRpNjBS+y-ZheD(!R;F}&^V_}b_gqH%tVZ5%%ziO7k^w=es+wZtK^i*vmrWNLMs{oWu_CIov|s1raZiS)>38>pYu;i+-t zI_DiNe6aA4KTZ2P09qPj(0~K4nUq^0+f(2$g`229zkG4jLzRvJUWE0oF1XHL4t3UN zDH466G56sy9hTZoAJB!C3;@F;ONxEk5u6Mv%zdo}Rq`=* zw1n7MOhfNSV48TS989ArIcj`C%Gk8~93~u>)!Yt2b4ZriKj9x2d`H2HQNJ=I>hkDlcZn zqRj>!;oRMTIOu zx|Zfsu~v76T{z7AC(jxj^c@tnJHZtGPsq$DE!8kqvkDx5W?KUJPL+!Ffpwfa+|5z5 zKPCiOPqZZrAG;2%OH0T$W|`C@C*!Z`@Wkop{CTjB&Tk`+{XPnt`ND`Haz;xV`H^RS zyXYtw@WlqTvToi;=mq1<-|IQ(gcOpU%)b#_46|IuWL#4$oYLbqwuk6=Q@xZaJSKVF zZcHs~ZBl;&lF3=+nK; zF`4gSCeZXlwmC_t4I`#PUNQ*)Uv&oGxMALip|sxv^lyVV73tKI7)+QY5=tEMas{vTD-BaTJ^*Y6gq~PU;F5X!sxqiq$iFCo+Uv7m%1w((=e}Vf*=dtds|6 zbX}91!G?C*KG03eHoN}RZS9DJxa&8YwNCT8?JxMXyZqZr13NA|GB{+vG`08C{V(yy zf*Lw$+tYSU_+dI`3n{bMrPdDb`A=Mkg!O=k>1|*3MC8j~- zXL79J4E=U^H=iBLTeHE_OKzE&dws8RNynsSJ!d;`zK?P92U{f)xvD7VQVosrXZrL+ z6lMVdD1YgL;%(1cq{#bS6yXmp|DS@nax#AqqlZhtUQdh<^2vr5`EpAO

LGYq)sa(w9^3-f}NHy=GR4v%t2YZly3m1G@5y`xBh_HGrD%f z>;|Ty?9FiJAc&UVD(StT4I` zfVQwxhE9bXE6r2mKO8Ag7{L^jCyqQb0QqKDPE=RAgqn8q1O^>(z7h5kE(6va%QqRZ zkIOmp(})rLSS(2{=C12e&@!W2=Jel-^_R``0xHO^+t!(oXbcv5yhD4g*$t_F)_5Dl zSVCgesW%;DtYPCFs{G;GX_o?1J3;QQPPv)rWw;>} zJ&KwnUqwNXloNXlK_+pNDfI~hON#SokVJb&ilg8d7^NWo2ZQymCqQMnjfi>ePibjr z-Z@q!?RGN$Mj}Nk){X_vaj6?Mj$>ACR*z|6MsXy3VZ^PFn@yHkPo(>m(iWepn8SC@ z>D2;R4m+gDRZ=SIX!b+CP(qE=JDIUkn=D$aUu+Ihn9-+k1LS3PreQg0N5eWIG@x${nC3v^7caS>1!PKNAY9J z#}E}Q9w#SP>(GY7Hbj&z4$Li6o5taBO|4+F`yS9zq*LJ<38wy4I>HA9(&GYrk4dLajKGww))BWli6Ln1A^Lda@N~p+snkb9C z@OthI+<##vp8!HVQT4Wk(=@zQ{OvZ$EKWS73+JHb)eYLGD-cqi6^|vd$<+IHuc?Nq zW7JertT~3))4?J|28n$I@nAD0c1%9C&IVhEZX~mUsf{efyS(XNG%ch;!N~d7S(Ri7 zb&=BuON95aVA&kLn6&MVU|x}xPMp7xwWxNU1wS+F6#y}1@^wQZB*(&ecT?RnQcI}Y z2*z!^!D?gDUhc@;M^OpLs4mq>C&p{}OWVv<)S9KMars@0JQ{c_ScGsFo3BJ)Irg++ zAWwypJdTO-_{Uh8m(Z!3KL7K{ZZzKHj;{M8I$mV>k znTM?sa0);^=X^cglL`uC+^J)M7nEa$w=VwFULg~%DJllw+7dJAj3{qnP5i3@wr7%y zjXp?Wl2%Th=my&3u?Q$RV6N5tzKMSPTsc#J+-cDDp~qFB6bL2C8AS7Y3PKtVhdhl) zIaLqH5+OnWPWSt(lQCgkN8lczc-V%_iZ{>#1%Z$N*>lu#S;0MZ$T2Y8Kg!U;hAZj> z6S#%$DQ_`Ic%Zr@?}GgjRXg@qTj^17n`65oJ@Wj0u1X8&+UVd|Xs?J+i_^GZ94m6= zUc96~Q`OJvlKB_Lr15*Yw_PUPEr?f?H&00b^-W%26mD)(n(rGGNfK9~2h=C>p-7BZ zFd&*&Msdu{w~(eyFOglwCPH^Rb}O(N7LtS+nnEwDx*pGD?|&9Si~M43a+*L(b0$5A zv`T`(G3xO;I_sx;FwTP21ZlfDpz zOo?}Vlgf~fo{YWm@n_JyD*frOg{XsvBA~|Tn4V6hu>Gd>89-rblfVJUaGvj6X%NZ} z$tFF9sx=4_$*c~G`9iPLGh@=sV+O{D2-t*K@J7H=`V+oVt}8?04WwU3h1BgS!f%1P zFak-T#7`TtLcR=Yz>g0R!ZQrH!YiZOQN=_V-UyncN1Rc18?KY?#O`v#JK+pq0K$~H z3D@v9DZF42R)b9#BBX{^$DOMlJ!g)Gc za{o-1e%F6NvgKq9tC8pV+9S$;9*zNv{J*)n&dmf~anP1)4~N%~h#c(=B#3*KgzhCKhFdgDoWi2IDog{RVyzK|Y`rCUs3T~pJMmdZJy4?b z&s5G=zhf**(t7Y^oC_mcTsE-{^}wiaoUu&?kojLKs>SJPxjcP>{a5CbXCx92AcBE) zHtqP}LjZ{W>PH?Tu(E0X=%{PBMW@F_?#7b&#!^q`<-5$ur+-q6 z{dn=(^UZw6*3-XM_(=@<1_*i&XM4=0t5u!gm6 z{UlmNGPKgO_;e;q9|#esq~Sq`<}%d{+sRmhvsA{5i*91=tub>OZZ%)xUA#4q$dDyy z1`w4%?OPLg3JeZb#cqSMO?*Xn%|-FCcuH2i2fn_{IFusub6;NQdN|7TD1N?%E8*g? z$apAt@cEe!I%jB=*q$p_3=t_5R0ph%{qaq+QDg!c99Y!Xa!&oDZOeis_ot)gNXr{l zdY$|So2Qed2Y7KMNBrS^E169kG%h<+z{Z_p_;shB!uY)>yAVcK=&!bg`lVg)4T1|7 z0}7FpfydVH4F87K@c!nEG+WGKm{Ouo)Slpl;#qcEIQ0zdMfLA#;dBxYw;p;KoVv6| z3_D5&7rJdG12CnDSvZUW?$UC6^UVSW^|vw|o-_4bz)(w5(3AiVhpeT(|=f#x_}E?s#qHZF#xA6AF_ujl$G z-jHD%q(d2}v2PhXx&6YWps~m(^+RXl91Q#xRRJBhjKl$FG4bk);|ag;ieUZ&!Ii3$ z(iGz1+0m7#g5>ASldBbNZL=ZHh=tmmJt$!71; zIML2GhEz1pg@1rQN(M^_691wAGkJ@Pga_05WuQ6! zG5RkGY2^`@(H~pp7&Ga+Pwh3L!Njj!-rc;^bTIfo5hP@H##1X8xUZJckrx>id`bAd3QUx9GuomqBYZ!uN1-&o zvTxC?;p8vL67&fW8fw(YOqt>L@bdLrEF*3OgYe$4n4{ zEB40LiU#6-0@5jdN`0w}N0qi@c0~oT2FP z)LNk&a82my?jv(tQpiMi$TK_L@lub#lsM$R{Dk?Ya@%%%huZkct~tSWM714c!45k}-ZLVA-bVM`>|_ZBbW_m-7| z3U%xrAhi}n?T(2F{_n4EZ10inkIFl#y09?7$uwBoJgqY8vylwev)fDOn;>0R!aEnV zBz%j0Mqpx~EZU3q@%+oV7;}|vt7$~ou@faEIq{p?FY$XXg&6*K)b_LP=}gi9`Bij3 zN`zEo|B6*|-;>S`rNa^BKRDbDAk>X#MsR`EvL>6bqU@SaDDs z8>bu@3YdRaWs*Te@G-UHjU%F~kTHw5(0PVJ+pwh#ha2u;DB+UMo@A5UYIl#5rtBV- zGX_hIpw}3C@H*Us(Cc-d#-gNrG#w$(9+S=GxO>3SR`SE2fHZ2KrDc#_C^$jI>Y}#; zMwY=R6@+dWi~0RXw(c@3GZ&%~9K(q&ee0Zw;pwL`E_tZak-#8^_b)Dpyi73^he?xV zXJ08&wh5-M&}qy4f7!D&=E)puDD(Nmg1d_(j`4LvxM5x_huNg-pGG%9rYqO6mImyJ@}*3Y>^3OvcnTG%EV1) zq_Ap?Z!Iw__7#D=pOWnQN$gB!Mr0!9yx|g<4icJh{cFOu3B8}&RiYm+Mb;VEK``LK zL(NcpcTiGieOIssSjr?ob}^``nNf&UcJhXyncO9m{6gD$kqSD`S69(aF8dkWz5>!9 zBLe4Sib7Hs2x_L2Ls6Ish$MGVKrGt5+_2zCyP1byaCg3upo+-I}R4&$m)8 zQ7|jc1Z^VWggpuQj*cP;>Zo9LS!VSzrqmZczaf;u`d0J(f%Z9r%An@s!e>n9%y=n!IZ_tVGu{Jmsbp}Fk%HJIU?a+-~bjfLTuH|JExA8EROowzr zqW9{YyZhR0a4clRK>1I4Ncx&WER~{iE;F^$T7K%X@3PGOA%6#Z%p3TS^&M;Dnjw@i z^o!$9nhcsmcHcY4?4j9+ofL_CWsZ4Hcch(rjsGfGD(nsH>w}^ERqGnz%iGj0j{g}h z7wMkJ-2Z2~eS>2!i}0~B63i;>SyFJU2+>VCS^AxaDOx%g6-t0eM^P<3+*z`ztvOqrG3)&#$K?& z_Y0wbWID47@cU`E1A6A&!`aZk0ZE@z-h#l1NqX2#`$Uev2gepW`rf8*!=rD5&;Jb{ zl08rU>dPo=K%-1Ao1~G-@4ve~y5#9E8x;TE0k5d^TC(=Zc>mwjW^c=+U-<9}b0ku~}gj z3sbW>R2M6DR!g#NUP;nxo>)@7*=RP{U18SDop6b2&PHce^&h97@xx3t+VK+!keE#} z;(Uf&89as9k8{$nkLbuB!-d7TP`_VJpL^Xs8OKB~ri$YUbW8fch64}7|0EWoT(TRj{ z*GT<7Y<7DsrCi79ZsM)z#c(!nNOGySOCkY1fAuQOq12&iUVC!a`#O;dBLf=d?&4*B zI~LgAO7E0qxK(uRTM;IgJ}+z^gD+bi-6I!3x{r9`l~%8TRP%UE0V8E*Sz>Nl1NVG<<7(wDHZ+HcOkQm$O&k+vyx)y)x{Pz!U8hS$*m zByc0h6BUI*BOpuL==P+H|Hx%`>7!W+1H!l9vi&)`V zyn2o9{z=lc+VX*!Vh~SF=)L}Z40XeG>LF6cP^b+R$NxSeUqbK^Q*UTalKzP8X%{9@RSCXm_NhF>{=S2 zi}ezam_^P`S!!-cyEW9y7DBbK93roz@Raccy*v}?mKXScU9E_4g;hBU7}zSofAFda zKYEe?{{I54 diff --git a/gradlew b/gradlew index 1aa94a426907..f5feea6d6b11 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 25da30dbdeee..9d21a21834d5 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ##########################################################################