CSVDownloadsController.java

1
package edu.ucsb.cs156.frontiers.controllers;
2
3
import com.opencsv.bean.StatefulBeanToCsv;
4
import com.opencsv.exceptions.CsvDataTypeMismatchException;
5
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
6
import edu.ucsb.cs156.frontiers.entities.Course;
7
import edu.ucsb.cs156.frontiers.errors.EntityNotFoundException;
8
import edu.ucsb.cs156.frontiers.models.CourseStaffDTO;
9
import edu.ucsb.cs156.frontiers.models.RosterStudentDTO;
10
import edu.ucsb.cs156.frontiers.repositories.CourseRepository;
11
import edu.ucsb.cs156.frontiers.services.CourseStaffDTOService;
12
import edu.ucsb.cs156.frontiers.services.RosterStudentDTOService;
13
import io.swagger.v3.oas.annotations.Operation;
14
import io.swagger.v3.oas.annotations.Parameter;
15
import io.swagger.v3.oas.annotations.media.Content;
16
import io.swagger.v3.oas.annotations.media.Schema;
17
import io.swagger.v3.oas.annotations.responses.ApiResponse;
18
import io.swagger.v3.oas.annotations.tags.Tag;
19
import java.io.IOException;
20
import java.io.OutputStreamWriter;
21
import java.io.Writer;
22
import java.nio.charset.StandardCharsets;
23
import java.util.List;
24
import lombok.extern.slf4j.Slf4j;
25
import org.springframework.beans.factory.annotation.Autowired;
26
import org.springframework.http.HttpHeaders;
27
import org.springframework.http.MediaType;
28
import org.springframework.http.ResponseEntity;
29
import org.springframework.security.access.prepost.PreAuthorize;
30
import org.springframework.web.bind.annotation.GetMapping;
31
import org.springframework.web.bind.annotation.RequestMapping;
32
import org.springframework.web.bind.annotation.RequestParam;
33
import org.springframework.web.bind.annotation.RestController;
34
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
35
36
@Tag(name = "CSV Downloads")
37
@RequestMapping("/api/csv")
38
@RestController
39
@Slf4j
40
public class CSVDownloadsController extends ApiController {
41
42
  @Autowired private CourseRepository courseRepository;
43
44
  @Autowired private CourseStaffDTOService courseStaffDTOService;
45
46
  @Autowired private RosterStudentDTOService rosterStudentDTOService;
47
48
  @Operation(
49
      summary = "Download CSV File of Roster Students",
50
      description = "Returns a CSV file as a response",
51
      responses = {
52
        @ApiResponse(
53
            responseCode = "200",
54
            description = "CSV file",
55
            content =
56
                @Content(
57
                    mediaType = "text/csv",
58
                    schema = @Schema(type = "string", format = "binary"))),
59
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
60
      })
61
  @GetMapping(value = "/rosterstudents", produces = "text/csv")
62
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
63
  public ResponseEntity<StreamingResponseBody> csvForQuarter(
64
      @Parameter(name = "courseId", description = "course id", example = "1") @RequestParam
65
          Long courseId)
66
      throws EntityNotFoundException, Exception, IOException {
67
    Course course =
68
        courseRepository
69
            .findById(courseId)
70 1 1. lambda$csvForQuarter$0 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$csvForQuarter$0 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
71
    StreamingResponseBody stream =
72
        (outputStream) -> {
73
          List<RosterStudentDTO> list = rosterStudentDTOService.getRosterStudentDTOs(courseId);
74
          try (Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
75
            try {
76
              StatefulBeanToCsv<RosterStudentDTO> beanToCsvWriter =
77
                  rosterStudentDTOService.getStatefulBeanToCSV(writer);
78 1 1. lambda$csvForQuarter$1 : removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED
              beanToCsvWriter.write(list);
79
            } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
80
              log.error("Error writing CSV file", e);
81
              throw new IOException("Error writing CSV file: " + e.getMessage());
82
            }
83
          }
84
        };
85
86 1 1. csvForQuarter : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::csvForQuarter → KILLED
    return ResponseEntity.ok()
87
        .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8"))
88
        .header(
89
            HttpHeaders.CONTENT_DISPOSITION,
90
            String.format("attachment;filename=%s_roster.csv", course.getCourseName()))
91
        .header(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8")
92
        .header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION)
93
        .body(stream);
94
  }
95
96
  @Operation(
97
      summary = "Download CSV File of Course Staff",
98
      description = "Returns a CSV file as a response",
99
      responses = {
100
        @ApiResponse(
101
            responseCode = "200",
102
            description = "CSV file",
103
            content =
104
                @Content(
105
                    mediaType = "text/csv",
106
                    schema = @Schema(type = "string", format = "binary"))),
107
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
108
      })
109
  @GetMapping(value = "/coursestaff", produces = "text/csv")
110
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
111
  public ResponseEntity<StreamingResponseBody> csvForCourseStaff(
112
      @Parameter(name = "courseId", description = "course id", example = "1") @RequestParam
113
          Long courseId)
114
      throws EntityNotFoundException, Exception, IOException {
115
    Course course =
116
        courseRepository
117
            .findById(courseId)
118 1 1. lambda$csvForCourseStaff$2 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$csvForCourseStaff$2 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
119
    StreamingResponseBody stream =
120
        (outputStream) -> {
121
          List<CourseStaffDTO> list = courseStaffDTOService.getCourseStaffDTOs(courseId);
122
          try (Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
123
            try {
124
              StatefulBeanToCsv<CourseStaffDTO> beanToCsvWriter =
125
                  courseStaffDTOService.getStatefulBeanToCSV(writer);
126 1 1. lambda$csvForCourseStaff$3 : removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED
              beanToCsvWriter.write(list);
127
            } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
128
              log.error("Error writing CSV file", e);
129
              throw new IOException("Error writing CSV file: " + e.getMessage());
130
            }
131
          }
132
        };
133
134 1 1. csvForCourseStaff : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::csvForCourseStaff → KILLED
    return ResponseEntity.ok()
135
        .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8"))
136
        .header(
137
            HttpHeaders.CONTENT_DISPOSITION,
138
            String.format("attachment;filename=%s_staff.csv", course.getCourseName()))
139
        .header(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8")
140
        .header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION)
141
        .body(stream);
142
  }
143
}

Mutations

70

1.1
Location : lambda$csvForQuarter$0
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_no_such_course()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$csvForQuarter$0 → KILLED

78

1.1
Location : lambda$csvForQuarter$1
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:mockMvcSRBTest()]
removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED

86

1.1
Location : csvForQuarter
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_csv_exception()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::csvForQuarter → KILLED

118

1.1
Location : lambda$csvForCourseStaff$2
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_no_such_course_staff_csv()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$csvForCourseStaff$2 → KILLED

126

1.1
Location : lambda$csvForCourseStaff$3
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:mockMvcCourseStaffCsvTest()]
removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED

134

1.1
Location : csvForCourseStaff
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_course_staff_csv_exception()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::csvForCourseStaff → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0