ConceptsYamlController.java

1
package edu.ucsb.cs.scaffold.controller;
2
3
import edu.ucsb.cs.scaffold.errors.EntityNotFoundException;
4
import edu.ucsb.cs.scaffold.services.ConceptYamlService;
5
import io.swagger.v3.oas.annotations.Operation;
6
import io.swagger.v3.oas.annotations.Parameter;
7
import io.swagger.v3.oas.annotations.tags.Tag;
8
import java.io.IOException;
9
import java.util.Map;
10
import lombok.RequiredArgsConstructor;
11
import org.springframework.http.HttpHeaders;
12
import org.springframework.http.HttpStatus;
13
import org.springframework.http.MediaType;
14
import org.springframework.http.ResponseEntity;
15
import org.springframework.security.access.prepost.PreAuthorize;
16
import org.springframework.web.bind.annotation.GetMapping;
17
import org.springframework.web.bind.annotation.PostMapping;
18
import org.springframework.web.bind.annotation.RequestParam;
19
import org.springframework.web.bind.annotation.RestController;
20
import org.springframework.web.multipart.MultipartFile;
21
22
/**
23
 * Download and upload a course's entire concept-graph content (concepts, subconcepts, prerequisite
24
 * edges, and practice problems) as a YAML file. See docs/yaml-format.md for the format.
25
 */
26
@Tag(name = "Concepts YAML")
27
@RestController
28
@RequiredArgsConstructor
29
public class ConceptsYamlController extends ApiController {
30
31
  private final ConceptYamlService conceptYamlService;
32
33
  @Operation(
34
      summary = "Download the course's concept-graph content as a YAML file",
35
      description =
36
          """
37
          Produces the course's concepts, subconcepts, prerequisite edges, and practice
38
          problems as a human-editable YAML document (see docs/yaml-format.md). The file
39
          can be edited and uploaded to this or another course.
40
          """)
41
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
42
  @GetMapping("/api/concepts/yaml/download")
43
  public ResponseEntity<String> downloadConceptsYaml(
44
      @Parameter(name = "courseId") @RequestParam Long courseId)
45
      throws EntityNotFoundException, IOException {
46
    String yaml = conceptYamlService.createYAML(courseId);
47 1 1. downloadConceptsYaml : replaced return value with null for edu/ucsb/cs/scaffold/controller/ConceptsYamlController::downloadConceptsYaml → KILLED
    return ResponseEntity.ok()
48
        .contentType(MediaType.parseMediaType("application/x-yaml"))
49
        .header(
50
            HttpHeaders.CONTENT_DISPOSITION,
51
            "attachment; filename=\"concepts-course-%d.yaml\"".formatted(courseId))
52
        .body(yaml);
53
  }
54
55
  @Operation(
56
      summary = "Replace the course's concept-graph content from an uploaded YAML file",
57
      description =
58
          """
59
          Replaces ALL of the course's concepts, subconcepts, prerequisite edges, and
60
          practice problems with the uploaded document (see docs/yaml-format.md), and
61
          deletes every user's saved per-course scaffold state, which would be stale.
62
          All-or-nothing: an invalid file changes nothing and responds 400 with every
63
          problem found listed under errors.
64
          """)
65
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
66
  @PostMapping(
67
      value = "/api/concepts/yaml/upload",
68
      consumes = {"multipart/form-data"})
69
  public ResponseEntity<Map<String, Object>> uploadConceptsYaml(
70
      @Parameter(name = "courseId") @RequestParam Long courseId,
71
      @Parameter(name = "file") @RequestParam("file") MultipartFile file)
72
      throws EntityNotFoundException, IOException {
73
    Map<String, Object> report =
74
        conceptYamlService.replaceFromYAML(courseId, file.getInputStream());
75
    HttpStatus status =
76 1 1. uploadConceptsYaml : negated conditional → KILLED
        Boolean.TRUE.equals(report.get("success")) ? HttpStatus.OK : HttpStatus.BAD_REQUEST;
77 1 1. uploadConceptsYaml : replaced return value with null for edu/ucsb/cs/scaffold/controller/ConceptsYamlController::uploadConceptsYaml → KILLED
    return ResponseEntity.status(status).body(report);
78
  }
79
}

Mutations

47

1.1
Location : downloadConceptsYaml
Killed by : edu.ucsb.cs.scaffold.controller.ConceptsYamlControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.ConceptsYamlControllerTests]/[method:download_returns_yaml_as_an_attachment()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/ConceptsYamlController::downloadConceptsYaml → KILLED

76

1.1
Location : uploadConceptsYaml
Killed by : edu.ucsb.cs.scaffold.controller.ConceptsYamlControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.ConceptsYamlControllerTests]/[method:upload_returns_400_with_the_report_when_the_file_is_invalid()]
negated conditional → KILLED

77

1.1
Location : uploadConceptsYaml
Killed by : edu.ucsb.cs.scaffold.controller.ConceptsYamlControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.ConceptsYamlControllerTests]/[method:upload_returns_400_with_the_report_when_the_file_is_invalid()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/ConceptsYamlController::uploadConceptsYaml → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0